fumadocs-openapi 10.5.0 → 10.6.0

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.
Files changed (111) hide show
  1. package/css/generated/shared.css +26 -21
  2. package/dist/generate-file.d.ts +10 -2
  3. package/dist/generate-file.d.ts.map +1 -1
  4. package/dist/generate-file.js +15 -3
  5. package/dist/generate-file.js.map +1 -1
  6. package/dist/playground/client.d.ts +27 -7
  7. package/dist/playground/client.d.ts.map +1 -1
  8. package/dist/playground/client.js +51 -44
  9. package/dist/playground/client.js.map +1 -1
  10. package/dist/playground/components/inputs.js +1 -1
  11. package/dist/playground/components/inputs.js.map +1 -1
  12. package/dist/playground/components/server-select.js +3 -4
  13. package/dist/playground/components/server-select.js.map +1 -1
  14. package/dist/playground/index.d.ts +1 -1
  15. package/dist/playground/index.d.ts.map +1 -1
  16. package/dist/playground/index.js +2 -2
  17. package/dist/playground/index.js.map +1 -1
  18. package/dist/playground/schema.d.ts.map +1 -1
  19. package/dist/playground/schema.js +10 -12
  20. package/dist/playground/schema.js.map +1 -1
  21. package/dist/requests/generators/python.d.ts +2 -1
  22. package/dist/requests/generators/python.d.ts.map +1 -1
  23. package/dist/requests/generators/python.js +13 -2
  24. package/dist/requests/generators/python.js.map +1 -1
  25. package/dist/scalar/index.d.ts +2 -1
  26. package/dist/scalar/index.d.ts.map +1 -1
  27. package/dist/server/create.d.ts +2 -0
  28. package/dist/server/create.d.ts.map +1 -1
  29. package/dist/server/create.js +11 -8
  30. package/dist/server/create.js.map +1 -1
  31. package/dist/server/source-api.d.ts +2 -0
  32. package/dist/server/source-api.d.ts.map +1 -1
  33. package/dist/server/source-api.js +10 -1
  34. package/dist/server/source-api.js.map +1 -1
  35. package/dist/types.d.ts +2 -4
  36. package/dist/types.d.ts.map +1 -1
  37. package/dist/ui/api-page.d.ts +1 -2
  38. package/dist/ui/api-page.d.ts.map +1 -1
  39. package/dist/ui/api-page.js +4 -6
  40. package/dist/ui/api-page.js.map +1 -1
  41. package/dist/ui/base.d.ts +20 -16
  42. package/dist/ui/base.d.ts.map +1 -1
  43. package/dist/ui/base.js +18 -9
  44. package/dist/ui/base.js.map +1 -1
  45. package/dist/ui/{full.client.js → client/full.js} +3 -3
  46. package/dist/ui/client/full.js.map +1 -0
  47. package/dist/ui/client/index.d.ts +1 -1
  48. package/dist/ui/client/index.js.map +1 -1
  49. package/dist/ui/client/storage-key.js.map +1 -1
  50. package/dist/ui/components/server-tab.js +43 -0
  51. package/dist/ui/components/server-tab.js.map +1 -0
  52. package/dist/ui/contexts/api.js +18 -35
  53. package/dist/ui/contexts/api.js.map +1 -1
  54. package/dist/ui/create-client.d.ts +26 -0
  55. package/dist/ui/create-client.d.ts.map +1 -0
  56. package/dist/ui/create-client.js +132 -0
  57. package/dist/ui/create-client.js.map +1 -0
  58. package/dist/ui/index.d.ts +10 -2
  59. package/dist/ui/index.d.ts.map +1 -0
  60. package/dist/ui/index.js +21 -1
  61. package/dist/ui/index.js.map +1 -0
  62. package/dist/ui/operation/client.js +44 -36
  63. package/dist/ui/operation/client.js.map +1 -1
  64. package/dist/ui/operation/{request-tabs.d.ts → get-example-requests.d.ts} +2 -4
  65. package/dist/ui/operation/get-example-requests.d.ts.map +1 -0
  66. package/dist/ui/operation/get-example-requests.js +83 -0
  67. package/dist/ui/operation/get-example-requests.js.map +1 -0
  68. package/dist/ui/operation/index.js +101 -63
  69. package/dist/ui/operation/index.js.map +1 -1
  70. package/dist/ui/operation/request-tabs.js +3 -81
  71. package/dist/ui/operation/request-tabs.js.map +1 -1
  72. package/dist/ui/operation/response-tabs.d.ts +1 -1
  73. package/dist/ui/operation/response-tabs.js +57 -54
  74. package/dist/ui/operation/response-tabs.js.map +1 -1
  75. package/dist/ui/operation/usage-tabs/client.js +7 -48
  76. package/dist/ui/operation/usage-tabs/client.js.map +1 -1
  77. package/dist/ui/operation/usage-tabs/index.js +14 -10
  78. package/dist/ui/operation/usage-tabs/index.js.map +1 -1
  79. package/dist/ui/operation/usage-tabs/lazy.js +1 -2
  80. package/dist/ui/operation/usage-tabs/lazy.js.map +1 -1
  81. package/dist/ui/schema/index.d.ts +1 -1
  82. package/dist/ui/schema/index.js +4 -2
  83. package/dist/ui/schema/index.js.map +1 -1
  84. package/dist/utils/pages/builder.d.ts +1 -1
  85. package/dist/utils/pages/builder.js +1 -1
  86. package/dist/utils/process-document.d.ts +1 -1
  87. package/dist/utils/process-document.js +1 -32
  88. package/dist/utils/process-document.js.map +1 -1
  89. package/dist/utils/schema/dereference.js +37 -0
  90. package/dist/utils/schema/dereference.js.map +1 -0
  91. package/dist/utils/{schema.d.ts → schema/index.d.ts} +3 -3
  92. package/dist/utils/schema/index.d.ts.map +1 -0
  93. package/dist/utils/{schema.js → schema/index.js} +3 -3
  94. package/dist/utils/schema/index.js.map +1 -0
  95. package/dist/utils/schema/resolve-ref.js +21 -0
  96. package/dist/utils/schema/resolve-ref.js.map +1 -0
  97. package/dist/utils/{schema-to-string.js → schema/to-string.js} +2 -2
  98. package/dist/utils/schema/to-string.js.map +1 -0
  99. package/package.json +5 -4
  100. package/dist/requests/to-python-object.js +0 -17
  101. package/dist/requests/to-python-object.js.map +0 -1
  102. package/dist/ui/full.client.js.map +0 -1
  103. package/dist/ui/full.d.ts +0 -11
  104. package/dist/ui/full.d.ts.map +0 -1
  105. package/dist/ui/full.js +0 -36
  106. package/dist/ui/full.js.map +0 -1
  107. package/dist/ui/operation/request-tabs.d.ts.map +0 -1
  108. package/dist/utils/schema-to-string.js.map +0 -1
  109. package/dist/utils/schema.d.ts.map +0 -1
  110. package/dist/utils/schema.js.map +0 -1
  111. /package/dist/utils/{schema-to-string.d.ts → schema/to-string.d.ts} +0 -0
@@ -1,92 +1,14 @@
1
1
  import { resolveRequestData } from "../../utils/url.js";
2
- import { getPreferredType, pickExample } from "../../utils/schema.js";
3
2
  import { MethodLabel } from "../components/method-label.js";
4
- import { encodeRequestData } from "../../requests/media/encode.js";
5
3
  import { I18nLabel } from "../client/i18n.js";
6
4
  import { AccordionContent, AccordionHeader, AccordionItem, AccordionTrigger, Accordions } from "../components/accordion.js";
7
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
- import { sample } from "openapi-sampler";
9
6
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "fumadocs-ui/components/tabs";
10
7
  //#region src/ui/operation/request-tabs.tsx
11
- function getExampleRequests(path, operation, ctx) {
12
- const requestBody = operation.requestBody;
13
- const media = requestBody?.content ? getPreferredType(requestBody.content) : null;
14
- const bodyOfType = media ? requestBody.content[media] : null;
15
- if (bodyOfType?.examples) {
16
- const result = [];
17
- for (const [key, value] of Object.entries(bodyOfType.examples)) {
18
- const data = getRequestData(path, operation, key, ctx);
19
- result.push({
20
- id: key,
21
- name: value.summary || key,
22
- description: value.description,
23
- data,
24
- encoded: encodeRequestData(data, ctx.mediaAdapters, operation.parameters ?? [])
25
- });
26
- }
27
- if (result.length > 0) return result;
28
- }
29
- const data = getRequestData(path, operation, null, ctx);
30
- return [{
31
- id: "_default",
32
- name: "Default",
33
- description: typeof bodyOfType?.schema === "object" ? bodyOfType.schema.description : void 0,
34
- data,
35
- encoded: encodeRequestData(data, ctx.mediaAdapters, operation.parameters ?? [])
36
- }];
37
- }
38
- function getRequestData(path, method, sampleKey, _ctx) {
39
- const result = {
40
- path: {},
41
- cookie: {},
42
- header: {},
43
- query: {},
44
- method: method.method
45
- };
46
- for (const param of method.parameters ?? []) {
47
- let value = pickExample(param);
48
- if (value === void 0 && param.required) {
49
- if (param.schema) value = sample(param.schema);
50
- else if (param.content) {
51
- const type = getPreferredType(param.content);
52
- const content = type ? param.content[type] : void 0;
53
- if (!content || !content.schema) throw new Error(`Cannot find "${param.name}" parameter info for media type "${type}" in ${path} ${method.method}`);
54
- value = sample(content.schema);
55
- }
56
- }
57
- switch (param.in) {
58
- case "cookie":
59
- result.cookie[param.name] = value;
60
- break;
61
- case "header":
62
- result.header[param.name] = value;
63
- break;
64
- case "query":
65
- result.query[param.name] = value;
66
- break;
67
- default: result.path[param.name] = value;
68
- }
69
- }
70
- if (method.requestBody?.content) {
71
- const body = method.requestBody.content;
72
- const type = getPreferredType(body);
73
- if (!type) throw new Error(`Cannot find body schema for ${path} ${method.method}: missing media type`);
74
- result.bodyMediaType = type;
75
- const bodyOfType = body[type];
76
- if (bodyOfType.examples && sampleKey) result.body = bodyOfType.examples[sampleKey].value;
77
- else if (bodyOfType.example) result.body = bodyOfType.example;
78
- else result.body = sample(bodyOfType?.schema ?? {}, {
79
- skipReadOnly: method.method !== "GET",
80
- skipWriteOnly: method.method === "GET",
81
- skipNonRequired: true
82
- });
83
- }
84
- return result;
85
- }
86
- async function RequestTabs({ path, operation, ctx }) {
8
+ function RequestTabs({ path, operation, examples, ctx }) {
87
9
  if (!operation.requestBody) return null;
88
10
  const { renderRequestTabs = renderRequestTabsDefault } = ctx.content ?? {};
89
- return renderRequestTabs(getExampleRequests(path, operation, ctx), {
11
+ return renderRequestTabs(examples, {
90
12
  ...ctx,
91
13
  route: path,
92
14
  operation
@@ -153,6 +75,6 @@ function renderRequestTabsDefault(items, ctx) {
153
75
  });
154
76
  }
155
77
  //#endregion
156
- export { RequestTabs, getExampleRequests };
78
+ export { RequestTabs };
157
79
 
158
80
  //# sourceMappingURL=request-tabs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"request-tabs.js","names":[],"sources":["../../../src/ui/operation/request-tabs.tsx"],"sourcesContent":["import type { MethodInformation, RenderContext } from '@/types';\nimport { getPreferredType, type NoReference, pickExample } from '@/utils/schema';\nimport { I18nLabel } from '@/ui/client/i18n';\nimport {\n AccordionContent,\n AccordionHeader,\n AccordionItem,\n Accordions,\n AccordionTrigger,\n} from '@/ui/components/accordion';\nimport { sample } from 'openapi-sampler';\nimport type { ReactNode } from 'react';\nimport type { RawRequestData, RequestData } from '@/requests/types';\nimport { encodeRequestData } from '@/requests/media/encode';\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from 'fumadocs-ui/components/tabs';\nimport { resolveRequestData } from '@/utils/url';\nimport { MethodLabel } from '../components/method-label';\n\nexport interface ExampleRequestItem {\n id: string;\n name: string;\n description?: string;\n data: RawRequestData;\n encoded: RequestData;\n}\n\nexport function getExampleRequests(\n path: string,\n operation: NoReference<MethodInformation>,\n ctx: RenderContext,\n): ExampleRequestItem[] {\n const requestBody = operation.requestBody;\n const media = requestBody?.content ? getPreferredType(requestBody.content) : null;\n const bodyOfType = media ? requestBody!.content![media] : null;\n\n if (bodyOfType?.examples) {\n const result: ExampleRequestItem[] = [];\n\n for (const [key, value] of Object.entries(bodyOfType.examples)) {\n const data = getRequestData(path, operation, key, ctx);\n\n result.push({\n id: key,\n name: value.summary || key,\n description: value.description,\n data,\n encoded: encodeRequestData(data, ctx.mediaAdapters, operation.parameters ?? []),\n });\n }\n\n if (result.length > 0) return result;\n }\n\n const data = getRequestData(path, operation, null, ctx);\n return [\n {\n id: '_default',\n name: 'Default',\n description:\n typeof bodyOfType?.schema === 'object' ? bodyOfType.schema.description : undefined,\n data,\n encoded: encodeRequestData(data, ctx.mediaAdapters, operation.parameters ?? []),\n },\n ];\n}\n\nfunction getRequestData(\n path: string,\n method: NoReference<MethodInformation>,\n sampleKey: string | null,\n _ctx: RenderContext,\n): RawRequestData {\n const result: RawRequestData = {\n path: {},\n cookie: {},\n header: {},\n query: {},\n method: method.method,\n };\n\n for (const param of method.parameters ?? []) {\n let value = pickExample(param as never);\n\n if (value === undefined && param.required) {\n if (param.schema) {\n value = sample(param.schema as object);\n } else if (param.content) {\n const type = getPreferredType(param.content);\n const content = type ? param.content[type] : undefined;\n if (!content || !content.schema)\n throw new Error(\n `Cannot find \"${param.name}\" parameter info for media type \"${type}\" in ${path} ${method.method}`,\n );\n\n value = sample(content.schema as object);\n }\n }\n\n switch (param.in) {\n case 'cookie':\n result.cookie[param.name!] = value;\n break;\n case 'header':\n result.header[param.name!] = value;\n break;\n case 'query':\n result.query[param.name!] = value;\n break;\n default:\n result.path[param.name!] = value;\n }\n }\n\n if (method.requestBody?.content) {\n const body = method.requestBody.content;\n const type = getPreferredType(body);\n if (!type)\n throw new Error(`Cannot find body schema for ${path} ${method.method}: missing media type`);\n result.bodyMediaType = type as RawRequestData['bodyMediaType'];\n const bodyOfType = body[type];\n\n if (bodyOfType.examples && sampleKey) {\n result.body = bodyOfType.examples[sampleKey].value;\n } else if (bodyOfType.example) {\n result.body = bodyOfType.example;\n } else {\n result.body = sample((bodyOfType?.schema ?? {}) as object, {\n skipReadOnly: method.method !== 'GET',\n skipWriteOnly: method.method === 'GET',\n skipNonRequired: true,\n });\n }\n }\n\n return result;\n}\n\nexport async function RequestTabs({\n path,\n operation,\n ctx,\n}: {\n path: string;\n operation: NoReference<MethodInformation>;\n ctx: RenderContext;\n}) {\n if (!operation.requestBody) return null;\n const { renderRequestTabs = renderRequestTabsDefault } = ctx.content ?? {};\n\n return renderRequestTabs(getExampleRequests(path, operation, ctx), {\n ...ctx,\n route: path,\n operation,\n });\n}\n\nfunction renderRequestTabsDefault(\n items: ExampleRequestItem[],\n ctx: RenderContext & {\n route: string;\n operation: NoReference<MethodInformation>;\n },\n) {\n function renderItem(item: ExampleRequestItem) {\n const requestData = item.data;\n const displayNames: Partial<Record<keyof RawRequestData, ReactNode>> = {\n body: (\n <>\n <I18nLabel label=\"titleRequestBody\" />\n <code className=\"text-xs text-fd-muted-foreground ms-auto\">\n {requestData.bodyMediaType}\n </code>\n </>\n ),\n cookie: <I18nLabel label=\"cookieParameters\" />,\n header: <I18nLabel label=\"headerParameters\" />,\n query: <I18nLabel label=\"queryParameters\" />,\n path: <I18nLabel label=\"pathParameters\" />,\n };\n\n return (\n <>\n {item.description && ctx.renderMarkdown(item.description)}\n <div className=\"flex flex-row gap-2 items-center justify-between\">\n <MethodLabel>{requestData.method}</MethodLabel>\n <code>{resolveRequestData(ctx.route, item.encoded)}</code>\n </div>\n\n <Accordions type=\"multiple\" className=\"mt-2\">\n {Object.entries(displayNames).map(([k, v]) => {\n const data = requestData[k as keyof RawRequestData];\n if (!data || Object.keys(data).length === 0) return;\n\n return (\n <AccordionItem key={k} value={k}>\n <AccordionHeader>\n <AccordionTrigger>{v}</AccordionTrigger>\n </AccordionHeader>\n <AccordionContent className=\"prose-no-margin\">\n {ctx.renderCodeBlock('json', JSON.stringify(data, null, 2))}\n </AccordionContent>\n </AccordionItem>\n );\n })}\n </Accordions>\n </>\n );\n }\n\n let children: ReactNode;\n if (items.length > 1) {\n children = (\n <Tabs defaultValue={items[0].id}>\n <TabsList>\n {items.map((item) => (\n <TabsTrigger key={item.id} value={item.id}>\n {item.id === '_default' ? <I18nLabel label=\"requestTabNameDefault\" /> : item.name}\n </TabsTrigger>\n ))}\n </TabsList>\n {items.map((item) => (\n <TabsContent key={item.id} value={item.id}>\n {renderItem(item)}\n </TabsContent>\n ))}\n </Tabs>\n );\n } else if (items.length === 1) {\n children = renderItem(items[0]);\n } else {\n children = (\n <p className=\"text-fd-muted-foreground text-xs\">\n <I18nLabel label=\"empty\" />\n </p>\n );\n }\n\n return (\n <div className=\"p-3 rounded-xl border prose-no-margin bg-fd-card text-fd-card-foreground shadow-md\">\n <p className=\"font-semibold border-b pb-2\">\n <I18nLabel label=\"titleRequestTabs\" />\n </p>\n {children}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"request-tabs.js","names":[],"sources":["../../../src/ui/operation/request-tabs.tsx"],"sourcesContent":["import type { MethodInformation, RenderContext } from '@/types';\nimport type { NoReference } from '@/utils/schema';\nimport { I18nLabel } from '@/ui/client/i18n';\nimport {\n AccordionContent,\n AccordionHeader,\n AccordionItem,\n Accordions,\n AccordionTrigger,\n} from '@/ui/components/accordion';\nimport type { ReactNode } from 'react';\nimport type { RawRequestData } from '@/requests/types';\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from 'fumadocs-ui/components/tabs';\nimport { resolveRequestData } from '@/utils/url';\nimport { MethodLabel } from '../components/method-label';\nimport type { ExampleRequestItem } from './get-example-requests';\n\nexport function RequestTabs({\n path,\n operation,\n examples,\n ctx,\n}: {\n path: string;\n examples: ExampleRequestItem[];\n operation: NoReference<MethodInformation>;\n ctx: RenderContext;\n}) {\n if (!operation.requestBody) return null;\n const { renderRequestTabs = renderRequestTabsDefault } = ctx.content ?? {};\n\n return renderRequestTabs(examples, {\n ...ctx,\n route: path,\n operation,\n });\n}\n\nfunction renderRequestTabsDefault(\n items: ExampleRequestItem[],\n ctx: RenderContext & {\n route: string;\n operation: NoReference<MethodInformation>;\n },\n) {\n function renderItem(item: ExampleRequestItem) {\n const requestData = item.data;\n const displayNames: Partial<Record<keyof RawRequestData, ReactNode>> = {\n body: (\n <>\n <I18nLabel label=\"titleRequestBody\" />\n <code className=\"text-xs text-fd-muted-foreground ms-auto\">\n {requestData.bodyMediaType}\n </code>\n </>\n ),\n cookie: <I18nLabel label=\"cookieParameters\" />,\n header: <I18nLabel label=\"headerParameters\" />,\n query: <I18nLabel label=\"queryParameters\" />,\n path: <I18nLabel label=\"pathParameters\" />,\n };\n\n return (\n <>\n {item.description && ctx.renderMarkdown(item.description)}\n <div className=\"flex flex-row gap-2 items-center justify-between\">\n <MethodLabel>{requestData.method}</MethodLabel>\n <code>{resolveRequestData(ctx.route, item.encoded)}</code>\n </div>\n\n <Accordions type=\"multiple\" className=\"mt-2\">\n {Object.entries(displayNames).map(([k, v]) => {\n const data = requestData[k as keyof RawRequestData];\n if (!data || Object.keys(data).length === 0) return;\n\n return (\n <AccordionItem key={k} value={k}>\n <AccordionHeader>\n <AccordionTrigger>{v}</AccordionTrigger>\n </AccordionHeader>\n <AccordionContent className=\"prose-no-margin\">\n {ctx.renderCodeBlock('json', JSON.stringify(data, null, 2))}\n </AccordionContent>\n </AccordionItem>\n );\n })}\n </Accordions>\n </>\n );\n }\n\n let children: ReactNode;\n if (items.length > 1) {\n children = (\n <Tabs defaultValue={items[0].id}>\n <TabsList>\n {items.map((item) => (\n <TabsTrigger key={item.id} value={item.id}>\n {item.id === '_default' ? <I18nLabel label=\"requestTabNameDefault\" /> : item.name}\n </TabsTrigger>\n ))}\n </TabsList>\n {items.map((item) => (\n <TabsContent key={item.id} value={item.id}>\n {renderItem(item)}\n </TabsContent>\n ))}\n </Tabs>\n );\n } else if (items.length === 1) {\n children = renderItem(items[0]);\n } else {\n children = (\n <p className=\"text-fd-muted-foreground text-xs\">\n <I18nLabel label=\"empty\" />\n </p>\n );\n }\n\n return (\n <div className=\"p-3 rounded-xl border prose-no-margin bg-fd-card text-fd-card-foreground shadow-md\">\n <p className=\"font-semibold border-b pb-2\">\n <I18nLabel label=\"titleRequestTabs\" />\n </p>\n {children}\n </div>\n );\n}\n"],"mappings":";;;;;;;AAiBA,SAAgB,YAAY,EAC1B,MACA,WACA,UACA,OAMC;AACD,KAAI,CAAC,UAAU,YAAa,QAAO;CACnC,MAAM,EAAE,oBAAoB,6BAA6B,IAAI,WAAW,EAAE;AAE1E,QAAO,kBAAkB,UAAU;EACjC,GAAG;EACH,OAAO;EACP;EACD,CAAC;;AAGJ,SAAS,yBACP,OACA,KAIA;CACA,SAAS,WAAW,MAA0B;EAC5C,MAAM,cAAc,KAAK;EACzB,MAAM,eAAiE;GACrE,MACE,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,WAAD,EAAW,OAAM,oBAAqB,CAAA,EACtC,oBAAC,QAAD;IAAM,WAAU;cACb,YAAY;IACR,CAAA,CACN,EAAA,CAAA;GAEL,QAAQ,oBAAC,WAAD,EAAW,OAAM,oBAAqB,CAAA;GAC9C,QAAQ,oBAAC,WAAD,EAAW,OAAM,oBAAqB,CAAA;GAC9C,OAAO,oBAAC,WAAD,EAAW,OAAM,mBAAoB,CAAA;GAC5C,MAAM,oBAAC,WAAD,EAAW,OAAM,kBAAmB,CAAA;GAC3C;AAED,SACE,qBAAA,UAAA,EAAA,UAAA;GACG,KAAK,eAAe,IAAI,eAAe,KAAK,YAAY;GACzD,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,aAAD,EAAA,UAAc,YAAY,QAAqB,CAAA,EAC/C,oBAAC,QAAD,EAAA,UAAO,mBAAmB,IAAI,OAAO,KAAK,QAAQ,EAAQ,CAAA,CACtD;;GAEN,oBAAC,YAAD;IAAY,MAAK;IAAW,WAAU;cACnC,OAAO,QAAQ,aAAa,CAAC,KAAK,CAAC,GAAG,OAAO;KAC5C,MAAM,OAAO,YAAY;AACzB,SAAI,CAAC,QAAQ,OAAO,KAAK,KAAK,CAAC,WAAW,EAAG;AAE7C,YACE,qBAAC,eAAD;MAAuB,OAAO;gBAA9B,CACE,oBAAC,iBAAD,EAAA,UACE,oBAAC,kBAAD,EAAA,UAAmB,GAAqB,CAAA,EACxB,CAAA,EAClB,oBAAC,kBAAD;OAAkB,WAAU;iBACzB,IAAI,gBAAgB,QAAQ,KAAK,UAAU,MAAM,MAAM,EAAE,CAAC;OAC1C,CAAA,CACL;QAPI,EAOJ;MAElB;IACS,CAAA;GACZ,EAAA,CAAA;;CAIP,IAAI;AACJ,KAAI,MAAM,SAAS,EACjB,YACE,qBAAC,MAAD;EAAM,cAAc,MAAM,GAAG;YAA7B,CACE,oBAAC,UAAD,EAAA,UACG,MAAM,KAAK,SACV,oBAAC,aAAD;GAA2B,OAAO,KAAK;aACpC,KAAK,OAAO,aAAa,oBAAC,WAAD,EAAW,OAAM,yBAA0B,CAAA,GAAG,KAAK;GACjE,EAFI,KAAK,GAET,CACd,EACO,CAAA,EACV,MAAM,KAAK,SACV,oBAAC,aAAD;GAA2B,OAAO,KAAK;aACpC,WAAW,KAAK;GACL,EAFI,KAAK,GAET,CACd,CACG;;UAEA,MAAM,WAAW,EAC1B,YAAW,WAAW,MAAM,GAAG;KAE/B,YACE,oBAAC,KAAD;EAAG,WAAU;YACX,oBAAC,WAAD,EAAW,OAAM,SAAU,CAAA;EACzB,CAAA;AAIR,QACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,oBAAC,KAAD;GAAG,WAAU;aACX,oBAAC,WAAD,EAAW,OAAM,oBAAqB,CAAA;GACpC,CAAA,EACH,SACG"}
@@ -1,4 +1,4 @@
1
- import { NoReference } from "../../utils/schema.js";
1
+ import { NoReference } from "../../utils/schema/index.js";
2
2
  import { ResponseObject } from "../../types.js";
3
3
  import { ReactNode } from "react";
4
4
 
@@ -1,73 +1,76 @@
1
- import { getPreferredType } from "../../utils/schema.js";
1
+ import { getPreferredType } from "../../utils/schema/index.js";
2
2
  import { I18nLabel } from "../client/i18n.js";
3
3
  import { AccordionContent, AccordionHeader, AccordionItem, AccordionTrigger, Accordions } from "../components/accordion.js";
4
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+ import { useMemo } from "react";
5
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
5
6
  import { sample } from "openapi-sampler";
6
7
  import { Tab, Tabs } from "fumadocs-ui/components/tabs";
7
8
  //#region src/ui/operation/response-tabs.tsx
8
9
  function ResponseTabs({ operation, ctx }) {
9
- if (!operation.responses) return null;
10
- const tabs = [];
11
- for (const [code, response] of Object.entries(operation.responses)) {
12
- const media = response.content ? getPreferredType(response.content) : null;
13
- const responseOfType = media ? response.content?.[media] : null;
14
- const tab = {
15
- code,
16
- response,
17
- mediaType: media
18
- };
19
- if (responseOfType?.examples) {
20
- tab.examples ??= [];
21
- for (const [key, sample] of Object.entries(responseOfType.examples)) tab.examples.push({
22
- label: sample?.summary ?? /* @__PURE__ */ jsx(I18nLabel, {
23
- label: "responseTabName",
24
- replacements: { key }
25
- }),
26
- sample: sample.value,
27
- description: sample?.description
28
- });
29
- } else if (responseOfType?.example || responseOfType?.schema) {
30
- tab.examples ??= [];
31
- tab.examples.push({
32
- label: /* @__PURE__ */ jsx(I18nLabel, { label: "responseTabNameDefault" }),
33
- sample: responseOfType.example ?? sample(responseOfType.schema)
34
- });
10
+ const tabs = useMemo(() => {
11
+ const tabs = [];
12
+ if (!operation.responses) return tabs;
13
+ for (const [code, response] of Object.entries(operation.responses)) {
14
+ const media = response.content ? getPreferredType(response.content) : null;
15
+ const responseOfType = media ? response.content?.[media] : null;
16
+ const tab = {
17
+ code,
18
+ response,
19
+ mediaType: media
20
+ };
21
+ if (responseOfType?.examples) {
22
+ tab.examples ??= [];
23
+ for (const [key, sample] of Object.entries(responseOfType.examples)) tab.examples.push({
24
+ label: sample?.summary ?? /* @__PURE__ */ jsx(I18nLabel, {
25
+ label: "responseTabName",
26
+ replacements: { key }
27
+ }),
28
+ sample: sample.value,
29
+ description: sample?.description
30
+ });
31
+ } else if (responseOfType?.example || responseOfType?.schema) {
32
+ tab.examples ??= [];
33
+ tab.examples.push({
34
+ label: /* @__PURE__ */ jsx(I18nLabel, { label: "responseTabNameDefault" }),
35
+ sample: responseOfType.example ?? sample(responseOfType.schema)
36
+ });
37
+ }
38
+ tabs.push(tab);
35
39
  }
36
- tabs.push(tab);
37
- }
40
+ return tabs;
41
+ }, [operation.responses]);
42
+ if (tabs.length === 0) return null;
38
43
  const { renderResponseTabs = renderResponseTabsDefault } = ctx.content ?? {};
39
44
  return renderResponseTabs(tabs, ctx);
40
45
  }
41
46
  function renderResponseTabsDefault(tabs, ctx) {
42
47
  function renderExampleContent(example) {
43
- return /* @__PURE__ */ jsxs(Fragment, { children: [example.description && ctx.renderMarkdown(example.description), ctx.renderCodeBlock("json", JSON.stringify(example.sample, null, 2))] });
48
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [example.description && ctx.renderMarkdown(example.description), ctx.renderCodeBlock("json", JSON.stringify(example.sample, null, 2))] });
44
49
  }
45
- async function renderResponse(tab) {
46
- const { examples = [] } = tab;
47
- let slot = /* @__PURE__ */ jsx(I18nLabel, { label: "empty" });
48
- if (examples.length > 1) slot = /* @__PURE__ */ jsx(Accordions, {
49
- type: "single",
50
- className: "pt-2",
51
- defaultValue: "0",
52
- children: examples.map((example, i) => /* @__PURE__ */ jsxs(AccordionItem, {
53
- value: i.toString(),
54
- children: [/* @__PURE__ */ jsx(AccordionHeader, { children: /* @__PURE__ */ jsx(AccordionTrigger, { children: example.label }) }), /* @__PURE__ */ jsx(AccordionContent, {
55
- className: "prose-no-margin",
56
- children: renderExampleContent(example)
57
- })]
58
- }, i))
59
- });
60
- else if (examples.length === 1) slot = renderExampleContent(examples[0]);
61
- return /* @__PURE__ */ jsx(Tab, {
62
- value: tab.code,
63
- children: slot
64
- });
65
- }
66
- if (tabs.length === 0) return null;
67
50
  return /* @__PURE__ */ jsx(Tabs, {
68
51
  groupId: "fumadocs_openapi_responses",
69
52
  items: tabs.map((tab) => tab.code),
70
- children: tabs.map(renderResponse)
53
+ children: tabs.map((tab) => {
54
+ const { examples = [] } = tab;
55
+ let slot = /* @__PURE__ */ jsx(I18nLabel, { label: "empty" });
56
+ if (examples.length > 1) slot = /* @__PURE__ */ jsx(Accordions, {
57
+ type: "single",
58
+ className: "pt-2",
59
+ defaultValue: "0",
60
+ children: examples.map((example, i) => /* @__PURE__ */ jsxs(AccordionItem, {
61
+ value: i.toString(),
62
+ children: [/* @__PURE__ */ jsx(AccordionHeader, { children: /* @__PURE__ */ jsx(AccordionTrigger, { children: example.label }) }), /* @__PURE__ */ jsx(AccordionContent, {
63
+ className: "prose-no-margin",
64
+ children: renderExampleContent(example)
65
+ })]
66
+ }, i))
67
+ });
68
+ else if (examples.length === 1) slot = renderExampleContent(examples[0]);
69
+ return /* @__PURE__ */ jsx(Tab, {
70
+ value: tab.code,
71
+ children: slot
72
+ }, tab.code);
73
+ })
71
74
  });
72
75
  }
73
76
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"response-tabs.js","names":[],"sources":["../../../src/ui/operation/response-tabs.tsx"],"sourcesContent":["import type { MethodInformation, RenderContext, ResponseObject } from '@/types';\nimport { getPreferredType, type NoReference } from '@/utils/schema';\nimport {\n AccordionContent,\n AccordionHeader,\n AccordionItem,\n Accordions,\n AccordionTrigger,\n} from '@/ui/components/accordion';\nimport { Tab, Tabs } from 'fumadocs-ui/components/tabs';\nimport { sample } from 'openapi-sampler';\nimport type { ReactNode } from 'react';\nimport { I18nLabel } from '@/ui/client/i18n';\n\nexport interface ResponseTab {\n /**\n * HTTP response code\n */\n code: string;\n\n response: NoReference<ResponseObject>;\n /**\n * media type of response\n */\n mediaType: string | null;\n\n examples?: ResponseExample[];\n}\n\ninterface ResponseExample {\n /**\n * generated/defined example data\n */\n sample: unknown;\n\n label: ReactNode;\n\n /**\n * description (in Markdown)\n */\n description?: string;\n}\n\nexport function ResponseTabs({\n operation,\n ctx,\n}: {\n operation: NoReference<MethodInformation>;\n ctx: RenderContext;\n}) {\n if (!operation.responses) return null;\n const tabs: ResponseTab[] = [];\n\n for (const [code, response] of Object.entries(operation.responses)) {\n const media = response.content ? getPreferredType(response.content) : null;\n const responseOfType = media ? response.content?.[media] : null;\n\n const tab: ResponseTab = {\n code,\n response,\n mediaType: media as string | null,\n };\n\n if (responseOfType?.examples) {\n tab.examples ??= [];\n\n for (const [key, sample] of Object.entries(responseOfType.examples)) {\n tab.examples.push({\n label: sample?.summary ?? <I18nLabel label=\"responseTabName\" replacements={{ key }} />,\n sample: sample.value,\n description: sample?.description,\n });\n }\n } else if (responseOfType?.example || responseOfType?.schema) {\n tab.examples ??= [];\n tab.examples.push({\n label: <I18nLabel label=\"responseTabNameDefault\" />,\n sample: responseOfType.example ?? sample(responseOfType.schema as object),\n });\n }\n\n tabs.push(tab);\n }\n const { renderResponseTabs = renderResponseTabsDefault } = ctx.content ?? {};\n\n return renderResponseTabs(tabs, ctx);\n}\n\nfunction renderResponseTabsDefault(\n tabs: ResponseTab[],\n ctx: RenderContext,\n): ReactNode | Promise<ReactNode> {\n function renderExampleContent(example: ResponseExample) {\n return (\n <>\n {example.description && ctx.renderMarkdown(example.description)}\n {ctx.renderCodeBlock('json', JSON.stringify(example.sample, null, 2))}\n </>\n );\n }\n\n async function renderResponse(tab: ResponseTab) {\n const { examples = [] } = tab;\n\n let slot: ReactNode = <I18nLabel label=\"empty\" />;\n if (examples.length > 1) {\n slot = (\n <Accordions type=\"single\" className=\"pt-2\" defaultValue=\"0\">\n {examples.map((example, i) => (\n <AccordionItem key={i} value={i.toString()}>\n <AccordionHeader>\n <AccordionTrigger>{example.label}</AccordionTrigger>\n </AccordionHeader>\n <AccordionContent className=\"prose-no-margin\">\n {renderExampleContent(example)}\n </AccordionContent>\n </AccordionItem>\n ))}\n </Accordions>\n );\n } else if (examples.length === 1) {\n slot = renderExampleContent(examples[0]);\n }\n\n return <Tab value={tab.code}>{slot}</Tab>;\n }\n\n if (tabs.length === 0) return null;\n\n return (\n <Tabs groupId=\"fumadocs_openapi_responses\" items={tabs.map((tab) => tab.code)}>\n {tabs.map(renderResponse)}\n </Tabs>\n );\n}\n"],"mappings":";;;;;;;AA2CA,SAAgB,aAAa,EAC3B,WACA,OAIC;AACD,KAAI,CAAC,UAAU,UAAW,QAAO;CACjC,MAAM,OAAsB,EAAE;AAE9B,MAAK,MAAM,CAAC,MAAM,aAAa,OAAO,QAAQ,UAAU,UAAU,EAAE;EAClE,MAAM,QAAQ,SAAS,UAAU,iBAAiB,SAAS,QAAQ,GAAG;EACtE,MAAM,iBAAiB,QAAQ,SAAS,UAAU,SAAS;EAE3D,MAAM,MAAmB;GACvB;GACA;GACA,WAAW;GACZ;AAED,MAAI,gBAAgB,UAAU;AAC5B,OAAI,aAAa,EAAE;AAEnB,QAAK,MAAM,CAAC,KAAK,WAAW,OAAO,QAAQ,eAAe,SAAS,CACjE,KAAI,SAAS,KAAK;IAChB,OAAO,QAAQ,WAAW,oBAAC,WAAD;KAAW,OAAM;KAAkB,cAAc,EAAE,KAAK;KAAI,CAAA;IACtF,QAAQ,OAAO;IACf,aAAa,QAAQ;IACtB,CAAC;aAEK,gBAAgB,WAAW,gBAAgB,QAAQ;AAC5D,OAAI,aAAa,EAAE;AACnB,OAAI,SAAS,KAAK;IAChB,OAAO,oBAAC,WAAD,EAAW,OAAM,0BAA2B,CAAA;IACnD,QAAQ,eAAe,WAAW,OAAO,eAAe,OAAiB;IAC1E,CAAC;;AAGJ,OAAK,KAAK,IAAI;;CAEhB,MAAM,EAAE,qBAAqB,8BAA8B,IAAI,WAAW,EAAE;AAE5E,QAAO,mBAAmB,MAAM,IAAI;;AAGtC,SAAS,0BACP,MACA,KACgC;CAChC,SAAS,qBAAqB,SAA0B;AACtD,SACE,qBAAA,UAAA,EAAA,UAAA,CACG,QAAQ,eAAe,IAAI,eAAe,QAAQ,YAAY,EAC9D,IAAI,gBAAgB,QAAQ,KAAK,UAAU,QAAQ,QAAQ,MAAM,EAAE,CAAC,CACpE,EAAA,CAAA;;CAIP,eAAe,eAAe,KAAkB;EAC9C,MAAM,EAAE,WAAW,EAAE,KAAK;EAE1B,IAAI,OAAkB,oBAAC,WAAD,EAAW,OAAM,SAAU,CAAA;AACjD,MAAI,SAAS,SAAS,EACpB,QACE,oBAAC,YAAD;GAAY,MAAK;GAAS,WAAU;GAAO,cAAa;aACrD,SAAS,KAAK,SAAS,MACtB,qBAAC,eAAD;IAAuB,OAAO,EAAE,UAAU;cAA1C,CACE,oBAAC,iBAAD,EAAA,UACE,oBAAC,kBAAD,EAAA,UAAmB,QAAQ,OAAyB,CAAA,EACpC,CAAA,EAClB,oBAAC,kBAAD;KAAkB,WAAU;eACzB,qBAAqB,QAAQ;KACb,CAAA,CACL;MAPI,EAOJ,CAChB;GACS,CAAA;WAEN,SAAS,WAAW,EAC7B,QAAO,qBAAqB,SAAS,GAAG;AAG1C,SAAO,oBAAC,KAAD;GAAK,OAAO,IAAI;aAAO;GAAW,CAAA;;AAG3C,KAAI,KAAK,WAAW,EAAG,QAAO;AAE9B,QACE,oBAAC,MAAD;EAAM,SAAQ;EAA6B,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK;YAC1E,KAAK,IAAI,eAAe;EACpB,CAAA"}
1
+ {"version":3,"file":"response-tabs.js","names":[],"sources":["../../../src/ui/operation/response-tabs.tsx"],"sourcesContent":["import type { MethodInformation, RenderContext, ResponseObject } from '@/types';\nimport { getPreferredType, type NoReference } from '@/utils/schema';\nimport {\n AccordionContent,\n AccordionHeader,\n AccordionItem,\n Accordions,\n AccordionTrigger,\n} from '@/ui/components/accordion';\nimport { Tab, Tabs } from 'fumadocs-ui/components/tabs';\nimport { sample } from 'openapi-sampler';\nimport { useMemo, type ReactNode } from 'react';\nimport { I18nLabel } from '@/ui/client/i18n';\n\nexport interface ResponseTab {\n /**\n * HTTP response code\n */\n code: string;\n\n response: NoReference<ResponseObject>;\n /**\n * media type of response\n */\n mediaType: string | null;\n\n examples?: ResponseExample[];\n}\n\ninterface ResponseExample {\n /**\n * generated/defined example data\n */\n sample: unknown;\n\n label: ReactNode;\n\n /**\n * description (in Markdown)\n */\n description?: string;\n}\n\nexport function ResponseTabs({\n operation,\n ctx,\n}: {\n operation: NoReference<MethodInformation>;\n ctx: RenderContext;\n}) {\n const tabs = useMemo(() => {\n const tabs: ResponseTab[] = [];\n if (!operation.responses) return tabs;\n\n for (const [code, response] of Object.entries(operation.responses)) {\n const media = response.content ? getPreferredType(response.content) : null;\n const responseOfType = media ? response.content?.[media] : null;\n\n const tab: ResponseTab = {\n code,\n response,\n mediaType: media as string | null,\n };\n\n if (responseOfType?.examples) {\n tab.examples ??= [];\n\n for (const [key, sample] of Object.entries(responseOfType.examples)) {\n tab.examples.push({\n label: sample?.summary ?? <I18nLabel label=\"responseTabName\" replacements={{ key }} />,\n sample: sample.value,\n description: sample?.description,\n });\n }\n } else if (responseOfType?.example || responseOfType?.schema) {\n tab.examples ??= [];\n tab.examples.push({\n label: <I18nLabel label=\"responseTabNameDefault\" />,\n sample: responseOfType.example ?? sample(responseOfType.schema as object),\n });\n }\n\n tabs.push(tab);\n }\n\n return tabs;\n }, [operation.responses]);\n\n if (tabs.length === 0) return null;\n\n const { renderResponseTabs = renderResponseTabsDefault } = ctx.content ?? {};\n\n return renderResponseTabs(tabs, ctx);\n}\n\nfunction renderResponseTabsDefault(tabs: ResponseTab[], ctx: RenderContext): ReactNode {\n function renderExampleContent(example: ResponseExample) {\n return (\n <>\n {example.description && ctx.renderMarkdown(example.description)}\n {ctx.renderCodeBlock('json', JSON.stringify(example.sample, null, 2))}\n </>\n );\n }\n\n return (\n <Tabs groupId=\"fumadocs_openapi_responses\" items={tabs.map((tab) => tab.code)}>\n {tabs.map((tab) => {\n const { examples = [] } = tab;\n\n let slot: ReactNode = <I18nLabel label=\"empty\" />;\n if (examples.length > 1) {\n slot = (\n <Accordions type=\"single\" className=\"pt-2\" defaultValue=\"0\">\n {examples.map((example, i) => (\n <AccordionItem key={i} value={i.toString()}>\n <AccordionHeader>\n <AccordionTrigger>{example.label}</AccordionTrigger>\n </AccordionHeader>\n <AccordionContent className=\"prose-no-margin\">\n {renderExampleContent(example)}\n </AccordionContent>\n </AccordionItem>\n ))}\n </Accordions>\n );\n } else if (examples.length === 1) {\n slot = renderExampleContent(examples[0]);\n }\n\n return (\n <Tab key={tab.code} value={tab.code}>\n {slot}\n </Tab>\n );\n })}\n </Tabs>\n );\n}\n"],"mappings":";;;;;;;;AA2CA,SAAgB,aAAa,EAC3B,WACA,OAIC;CACD,MAAM,OAAO,cAAc;EACzB,MAAM,OAAsB,EAAE;AAC9B,MAAI,CAAC,UAAU,UAAW,QAAO;AAEjC,OAAK,MAAM,CAAC,MAAM,aAAa,OAAO,QAAQ,UAAU,UAAU,EAAE;GAClE,MAAM,QAAQ,SAAS,UAAU,iBAAiB,SAAS,QAAQ,GAAG;GACtE,MAAM,iBAAiB,QAAQ,SAAS,UAAU,SAAS;GAE3D,MAAM,MAAmB;IACvB;IACA;IACA,WAAW;IACZ;AAED,OAAI,gBAAgB,UAAU;AAC5B,QAAI,aAAa,EAAE;AAEnB,SAAK,MAAM,CAAC,KAAK,WAAW,OAAO,QAAQ,eAAe,SAAS,CACjE,KAAI,SAAS,KAAK;KAChB,OAAO,QAAQ,WAAW,oBAAC,WAAD;MAAW,OAAM;MAAkB,cAAc,EAAE,KAAK;MAAI,CAAA;KACtF,QAAQ,OAAO;KACf,aAAa,QAAQ;KACtB,CAAC;cAEK,gBAAgB,WAAW,gBAAgB,QAAQ;AAC5D,QAAI,aAAa,EAAE;AACnB,QAAI,SAAS,KAAK;KAChB,OAAO,oBAAC,WAAD,EAAW,OAAM,0BAA2B,CAAA;KACnD,QAAQ,eAAe,WAAW,OAAO,eAAe,OAAiB;KAC1E,CAAC;;AAGJ,QAAK,KAAK,IAAI;;AAGhB,SAAO;IACN,CAAC,UAAU,UAAU,CAAC;AAEzB,KAAI,KAAK,WAAW,EAAG,QAAO;CAE9B,MAAM,EAAE,qBAAqB,8BAA8B,IAAI,WAAW,EAAE;AAE5E,QAAO,mBAAmB,MAAM,IAAI;;AAGtC,SAAS,0BAA0B,MAAqB,KAA+B;CACrF,SAAS,qBAAqB,SAA0B;AACtD,SACE,qBAAA,YAAA,EAAA,UAAA,CACG,QAAQ,eAAe,IAAI,eAAe,QAAQ,YAAY,EAC9D,IAAI,gBAAgB,QAAQ,KAAK,UAAU,QAAQ,QAAQ,MAAM,EAAE,CAAC,CACpE,EAAA,CAAA;;AAIP,QACE,oBAAC,MAAD;EAAM,SAAQ;EAA6B,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK;YAC1E,KAAK,KAAK,QAAQ;GACjB,MAAM,EAAE,WAAW,EAAE,KAAK;GAE1B,IAAI,OAAkB,oBAAC,WAAD,EAAW,OAAM,SAAU,CAAA;AACjD,OAAI,SAAS,SAAS,EACpB,QACE,oBAAC,YAAD;IAAY,MAAK;IAAS,WAAU;IAAO,cAAa;cACrD,SAAS,KAAK,SAAS,MACtB,qBAAC,eAAD;KAAuB,OAAO,EAAE,UAAU;eAA1C,CACE,oBAAC,iBAAD,EAAA,UACE,oBAAC,kBAAD,EAAA,UAAmB,QAAQ,OAAyB,CAAA,EACpC,CAAA,EAClB,oBAAC,kBAAD;MAAkB,WAAU;gBACzB,qBAAqB,QAAQ;MACb,CAAA,CACL;OAPI,EAOJ,CAChB;IACS,CAAA;YAEN,SAAS,WAAW,EAC7B,QAAO,qBAAqB,SAAS,GAAG;AAG1C,UACE,oBAAC,KAAD;IAAoB,OAAO,IAAI;cAC5B;IACG,EAFI,IAAI,KAER;IAER;EACG,CAAA"}
@@ -1,55 +1,14 @@
1
1
  "use client";
2
2
  import { joinURL, resolveRequestData, resolveServerUrl, withBase } from "../../../utils/url.js";
3
- import { useApiContext, useServerSelectContext } from "../../contexts/api.js";
3
+ import { useApiContext, useServerContext } from "../../contexts/api.js";
4
4
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../components/select.js";
5
5
  import { ClientCodeBlock } from "../../components/codeblock.js";
6
- import { createContext, use, useEffect, useMemo, useRef, useState } from "react";
6
+ import { useOperationContext } from "../client.js";
7
+ import { useEffect, useMemo, useState } from "react";
7
8
  import { jsx, jsxs } from "react/jsx-runtime";
8
9
  //#region src/ui/operation/usage-tabs/client.tsx
9
- const Context = createContext(null);
10
- function UsageTabsProvider({ route, examples, defaultExampleId, children }) {
11
- const [example, setExample] = useState(() => defaultExampleId ?? examples.at(0)?.id);
12
- const listeners = useRef([]);
13
- return /* @__PURE__ */ jsx(Context, {
14
- value: useMemo(() => ({
15
- example,
16
- route,
17
- setExample(newKey) {
18
- const example = examples.find((example) => example.id === newKey);
19
- if (!example) return;
20
- setExample(newKey);
21
- for (const listener of listeners.current) listener(example.data, example.encoded);
22
- },
23
- examples,
24
- setExampleData(data, encoded) {
25
- for (const item of examples) if (item.id === example) {
26
- item.data = data;
27
- item.encoded = encoded;
28
- break;
29
- }
30
- for (const listener of listeners.current) listener(data, encoded);
31
- },
32
- removeListener(listener) {
33
- listeners.current = listeners.current.filter((item) => item !== listener);
34
- },
35
- addListener(listener) {
36
- const active = examples.find((item) => item.id === example);
37
- listener(active.data, active.encoded);
38
- listeners.current.push(listener);
39
- }
40
- }), [
41
- example,
42
- route,
43
- examples
44
- ]),
45
- children
46
- });
47
- }
48
- function useExampleRequests() {
49
- return use(Context);
50
- }
51
10
  function UsageTabsSelector() {
52
- const { example: key, setExample: setKey, examples } = useExampleRequests();
11
+ const { example: key, setExample: setKey, examples } = useOperationContext();
53
12
  const { APIExampleSelector: Override } = useApiContext().client.operation ?? {};
54
13
  if (Override) return /* @__PURE__ */ jsx(Override, {
55
14
  items: examples,
@@ -84,8 +43,8 @@ function UsageTabsSelector() {
84
43
  }
85
44
  function UsageTab({ id, lang, _client }) {
86
45
  const { mediaAdapters, codeUsages } = useApiContext();
87
- const { examples, example: selectedExampleId, route, addListener, removeListener } = useExampleRequests();
88
- const { server } = useServerSelectContext();
46
+ const { examples, example: selectedExampleId, route, addListener, removeListener } = useOperationContext();
47
+ const { server } = useServerContext();
89
48
  const codegen = codeUsages.get(id);
90
49
  const [data, setData] = useState(() => examples.find((example) => example.id === selectedExampleId)?.encoded);
91
50
  useEffect(() => {
@@ -126,6 +85,6 @@ function UsageTab({ id, lang, _client }) {
126
85
  });
127
86
  }
128
87
  //#endregion
129
- export { UsageTab, UsageTabsProvider, UsageTabsSelector, useExampleRequests };
88
+ export { UsageTab, UsageTabsSelector };
130
89
 
131
90
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":[],"sources":["../../../../src/ui/operation/usage-tabs/client.tsx"],"sourcesContent":["'use client';\nimport { useApiContext, useServerSelectContext } from '@/ui/contexts/api';\nimport { joinURL, withBase, resolveServerUrl, resolveRequestData } from '@/utils/url';\nimport {\n Select,\n SelectTrigger,\n SelectValue,\n SelectContent,\n SelectItem,\n} from '@/ui/components/select';\nimport { useState, useEffect, useMemo, createContext, ReactNode, useRef, use } from 'react';\nimport type { ExampleRequestItem } from '../request-tabs';\nimport type { RawRequestData, RequestData } from '@/requests/types';\nimport type { CodeUsageGenerator } from '@/requests/generators';\nimport { ClientCodeBlock } from '@/ui/components/codeblock';\n\nexport type ExampleUpdateListener = (data: RawRequestData, encoded: RequestData) => void;\n\nconst Context = createContext<{\n route: string;\n examples: ExampleRequestItem[];\n example: string | undefined;\n setExample: (id: string) => void;\n setExampleData: (data: RawRequestData, encoded: RequestData) => void;\n\n addListener: (listener: ExampleUpdateListener) => void;\n removeListener: (listener: ExampleUpdateListener) => void;\n} | null>(null);\n\nexport function UsageTabsProvider({\n route,\n examples,\n defaultExampleId,\n children,\n}: {\n route: string;\n examples: ExampleRequestItem[];\n defaultExampleId?: string;\n children: ReactNode;\n}) {\n const [example, setExample] = useState(() => defaultExampleId ?? examples.at(0)?.id);\n const listeners = useRef<ExampleUpdateListener[]>([]);\n\n return (\n <Context\n value={useMemo(\n () => ({\n example,\n route,\n setExample(newKey: string) {\n const example = examples.find((example) => example.id === newKey);\n if (!example) return;\n\n setExample(newKey);\n for (const listener of listeners.current) {\n listener(example.data, example.encoded);\n }\n },\n examples,\n setExampleData(data, encoded) {\n for (const item of examples) {\n if (item.id === example) {\n // persistent changes\n item.data = data;\n item.encoded = encoded;\n break;\n }\n }\n\n for (const listener of listeners.current) {\n listener(data, encoded);\n }\n },\n removeListener(listener) {\n listeners.current = listeners.current.filter((item) => item !== listener);\n },\n addListener(listener) {\n // initial call to listeners to ensure their data is the latest\n // this is necessary to avoid race conditions between `useEffect()`\n const active = examples.find((item) => item.id === example)!;\n\n listener(active.data, active.encoded);\n listeners.current.push(listener);\n },\n }),\n [example, route, examples],\n )}\n >\n {children}\n </Context>\n );\n}\n\nexport function useExampleRequests() {\n return use(Context)!;\n}\n\nexport function UsageTabsSelector() {\n const { example: key, setExample: setKey, examples } = useExampleRequests();\n const { APIExampleSelector: Override } = useApiContext().client.operation ?? {};\n\n if (Override) {\n return <Override items={examples} value={key} onValueChange={setKey} />;\n }\n\n function renderItem(item: ExampleRequestItem) {\n return (\n <div>\n <span className=\"font-medium text-sm\">{item.name}</span>\n <span className=\"text-fd-muted-foreground\">{item.description}</span>\n </div>\n );\n }\n\n if (examples.length === 1) return null;\n const selected = examples.find((item) => item.id === key);\n return (\n <Select value={key} onValueChange={setKey}>\n <SelectTrigger className=\"not-prose mb-2\">\n {selected && <SelectValue asChild>{renderItem(selected)}</SelectValue>}\n </SelectTrigger>\n <SelectContent>\n {examples.map((item) => (\n <SelectItem key={item.id} value={item.id}>\n {renderItem(item)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n );\n}\n\nexport function UsageTab({\n id,\n lang,\n _client,\n}: Pick<CodeUsageGenerator, 'lang' | '_client'> & { id: string }) {\n const { mediaAdapters, codeUsages } = useApiContext();\n const {\n examples,\n example: selectedExampleId,\n route,\n addListener,\n removeListener,\n } = useExampleRequests();\n const { server } = useServerSelectContext();\n const codegen = codeUsages.get(id);\n const [data, setData] = useState(\n () => examples.find((example) => example.id === selectedExampleId)?.encoded,\n );\n\n useEffect(() => {\n const listener: ExampleUpdateListener = (_, encoded) => setData(encoded);\n\n addListener(listener);\n return () => {\n removeListener(listener);\n };\n }, [addListener, removeListener]);\n\n const code = useMemo(() => {\n if (!data) return;\n const url = joinURL(\n withBase(\n server ? resolveServerUrl(server.url, server.variables) : '/',\n typeof window !== 'undefined' ? window.location.origin : 'https://loading',\n ),\n resolveRequestData(route, data),\n );\n\n if (_client) {\n const { generate, serverContext } = _client;\n if (typeof generate === 'string') return generate;\n return generate(url, data, {\n mediaAdapters,\n server: serverContext,\n });\n }\n\n if (!codegen) return;\n return codegen.generate(url, data, {\n mediaAdapters,\n server: null,\n });\n }, [data, server, route, _client, codegen, mediaAdapters]);\n\n if (!code) return null;\n\n return <ClientCodeBlock lang={lang} code={code} />;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","names":[],"sources":["../../../../src/ui/operation/usage-tabs/client.tsx"],"sourcesContent":["'use client';\nimport { useApiContext, useServerContext } from '@/ui/contexts/api';\nimport { joinURL, withBase, resolveServerUrl, resolveRequestData } from '@/utils/url';\nimport {\n Select,\n SelectTrigger,\n SelectValue,\n SelectContent,\n SelectItem,\n} from '@/ui/components/select';\nimport { useState, useEffect, useMemo } from 'react';\nimport type { CodeUsageGenerator } from '@/requests/generators';\nimport { ClientCodeBlock } from '@/ui/components/codeblock';\nimport { type ExampleUpdateListener, useOperationContext } from '../client';\nimport type { ExampleRequestItem } from '../get-example-requests';\n\nexport function UsageTabsSelector() {\n const { example: key, setExample: setKey, examples } = useOperationContext();\n const { APIExampleSelector: Override } = useApiContext().client.operation ?? {};\n\n if (Override) {\n return <Override items={examples} value={key} onValueChange={setKey} />;\n }\n\n function renderItem(item: ExampleRequestItem) {\n return (\n <div>\n <span className=\"font-medium text-sm\">{item.name}</span>\n <span className=\"text-fd-muted-foreground\">{item.description}</span>\n </div>\n );\n }\n\n if (examples.length === 1) return null;\n const selected = examples.find((item) => item.id === key);\n return (\n <Select value={key} onValueChange={setKey}>\n <SelectTrigger className=\"not-prose mb-2\">\n {selected && <SelectValue asChild>{renderItem(selected)}</SelectValue>}\n </SelectTrigger>\n <SelectContent>\n {examples.map((item) => (\n <SelectItem key={item.id} value={item.id}>\n {renderItem(item)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n );\n}\n\nexport function UsageTab({\n id,\n lang,\n _client,\n}: Pick<CodeUsageGenerator, 'lang' | '_client'> & { id: string }) {\n const { mediaAdapters, codeUsages } = useApiContext();\n const {\n examples,\n example: selectedExampleId,\n route,\n addListener,\n removeListener,\n } = useOperationContext();\n const { server } = useServerContext();\n const codegen = codeUsages.get(id);\n const [data, setData] = useState(\n () => examples.find((example) => example.id === selectedExampleId)?.encoded,\n );\n\n useEffect(() => {\n const listener: ExampleUpdateListener = (_, encoded) => setData(encoded);\n\n addListener(listener);\n return () => {\n removeListener(listener);\n };\n }, [addListener, removeListener]);\n\n const code = useMemo(() => {\n if (!data) return;\n const url = joinURL(\n withBase(\n server ? resolveServerUrl(server.url, server.variables) : '/',\n typeof window !== 'undefined' ? window.location.origin : 'https://loading',\n ),\n resolveRequestData(route, data),\n );\n\n if (_client) {\n const { generate, serverContext } = _client;\n if (typeof generate === 'string') return generate;\n return generate(url, data, {\n mediaAdapters,\n server: serverContext,\n });\n }\n\n if (!codegen) return;\n return codegen.generate(url, data, {\n mediaAdapters,\n server: null,\n });\n }, [data, server, route, _client, codegen, mediaAdapters]);\n\n if (!code) return null;\n\n return <ClientCodeBlock lang={lang} code={code} />;\n}\n"],"mappings":";;;;;;;;;AAgBA,SAAgB,oBAAoB;CAClC,MAAM,EAAE,SAAS,KAAK,YAAY,QAAQ,aAAa,qBAAqB;CAC5E,MAAM,EAAE,oBAAoB,aAAa,eAAe,CAAC,OAAO,aAAa,EAAE;AAE/E,KAAI,SACF,QAAO,oBAAC,UAAD;EAAU,OAAO;EAAU,OAAO;EAAK,eAAe;EAAU,CAAA;CAGzE,SAAS,WAAW,MAA0B;AAC5C,SACE,qBAAC,OAAD,EAAA,UAAA,CACE,oBAAC,QAAD;GAAM,WAAU;aAAuB,KAAK;GAAY,CAAA,EACxD,oBAAC,QAAD;GAAM,WAAU;aAA4B,KAAK;GAAmB,CAAA,CAChE,EAAA,CAAA;;AAIV,KAAI,SAAS,WAAW,EAAG,QAAO;CAClC,MAAM,WAAW,SAAS,MAAM,SAAS,KAAK,OAAO,IAAI;AACzD,QACE,qBAAC,QAAD;EAAQ,OAAO;EAAK,eAAe;YAAnC,CACE,oBAAC,eAAD;GAAe,WAAU;aACtB,YAAY,oBAAC,aAAD;IAAa,SAAA;cAAS,WAAW,SAAS;IAAe,CAAA;GACxD,CAAA,EAChB,oBAAC,eAAD,EAAA,UACG,SAAS,KAAK,SACb,oBAAC,YAAD;GAA0B,OAAO,KAAK;aACnC,WAAW,KAAK;GACN,EAFI,KAAK,GAET,CACb,EACY,CAAA,CACT;;;AAIb,SAAgB,SAAS,EACvB,IACA,MACA,WACgE;CAChE,MAAM,EAAE,eAAe,eAAe,eAAe;CACrD,MAAM,EACJ,UACA,SAAS,mBACT,OACA,aACA,mBACE,qBAAqB;CACzB,MAAM,EAAE,WAAW,kBAAkB;CACrC,MAAM,UAAU,WAAW,IAAI,GAAG;CAClC,MAAM,CAAC,MAAM,WAAW,eAChB,SAAS,MAAM,YAAY,QAAQ,OAAO,kBAAkB,EAAE,QACrE;AAED,iBAAgB;EACd,MAAM,YAAmC,GAAG,YAAY,QAAQ,QAAQ;AAExE,cAAY,SAAS;AACrB,eAAa;AACX,kBAAe,SAAS;;IAEzB,CAAC,aAAa,eAAe,CAAC;CAEjC,MAAM,OAAO,cAAc;AACzB,MAAI,CAAC,KAAM;EACX,MAAM,MAAM,QACV,SACE,SAAS,iBAAiB,OAAO,KAAK,OAAO,UAAU,GAAG,KAC1D,OAAO,WAAW,cAAc,OAAO,SAAS,SAAS,kBAC1D,EACD,mBAAmB,OAAO,KAAK,CAChC;AAED,MAAI,SAAS;GACX,MAAM,EAAE,UAAU,kBAAkB;AACpC,OAAI,OAAO,aAAa,SAAU,QAAO;AACzC,UAAO,SAAS,KAAK,MAAM;IACzB;IACA,QAAQ;IACT,CAAC;;AAGJ,MAAI,CAAC,QAAS;AACd,SAAO,QAAQ,SAAS,KAAK,MAAM;GACjC;GACA,QAAQ;GACT,CAAC;IACD;EAAC;EAAM;EAAQ;EAAO;EAAS;EAAS;EAAc,CAAC;AAE1D,KAAI,CAAC,KAAM,QAAO;AAElB,QAAO,oBAAC,iBAAD;EAAuB;EAAY;EAAQ,CAAA"}
@@ -2,10 +2,11 @@ import { createCodeUsageGeneratorRegistry } from "../../../requests/generators/i
2
2
  import { registerDefault } from "../../../requests/generators/all.js";
3
3
  import { UsageTabLazy, UsageTabsSelectorLazy } from "./lazy.js";
4
4
  import { ResponseTabs } from "../response-tabs.js";
5
+ import { useMemo } from "react";
5
6
  import { jsx, jsxs } from "react/jsx-runtime";
6
7
  import { CodeBlockTab, CodeBlockTabs, CodeBlockTabsList, CodeBlockTabsTrigger } from "fumadocs-ui/components/codeblock";
7
8
  //#region src/ui/operation/usage-tabs/index.tsx
8
- async function UsageTabs({ method, ctx }) {
9
+ function UsageTabs({ method, ctx }) {
9
10
  let { renderAPIExampleUsageTabs, renderAPIExampleLayout } = ctx.content ?? {};
10
11
  renderAPIExampleLayout ??= (slots) => {
11
12
  return /* @__PURE__ */ jsxs("div", {
@@ -36,17 +37,20 @@ async function UsageTabs({ method, ctx }) {
36
37
  }, id))]
37
38
  });
38
39
  };
39
- let registry;
40
- if (ctx.codeUsages) registry = createCodeUsageGeneratorRegistry(ctx.codeUsages);
41
- else {
42
- registry = createCodeUsageGeneratorRegistry();
43
- registerDefault(registry);
44
- }
45
- for (const gen of await ctx.generateCodeSamples?.(method) ?? []) registry.addInline(gen);
46
- if (method["x-codeSamples"]) for (const sample of method["x-codeSamples"]) registry.addInline(sample);
40
+ const registry = useMemo(() => {
41
+ let registry;
42
+ if (ctx.codeUsages) registry = createCodeUsageGeneratorRegistry(ctx.codeUsages);
43
+ else {
44
+ registry = createCodeUsageGeneratorRegistry();
45
+ registerDefault(registry);
46
+ }
47
+ for (const gen of ctx.generateCodeSamples?.(method) ?? []) registry.addInline(gen);
48
+ if (method["x-codeSamples"]) for (const sample of method["x-codeSamples"]) registry.addInline(sample);
49
+ return registry;
50
+ }, [ctx, method]);
47
51
  return renderAPIExampleLayout({
48
52
  selector: method["x-exclusiveCodeSample"] ? null : /* @__PURE__ */ jsx(UsageTabsSelectorLazy, {}),
49
- usageTabs: await renderAPIExampleUsageTabs(registry, ctx),
53
+ usageTabs: renderAPIExampleUsageTabs(registry, ctx),
50
54
  responseTabs: /* @__PURE__ */ jsx(ResponseTabs, {
51
55
  operation: method,
52
56
  ctx
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/ui/operation/usage-tabs/index.tsx"],"sourcesContent":["import type { MethodInformation, RenderContext } from '@/types';\nimport type { CodeUsageGeneratorFn } from '@/requests/generators';\nimport {\n type CodeUsageGeneratorRegistry,\n createCodeUsageGeneratorRegistry,\n} from '@/requests/generators';\nimport {\n CodeBlockTab,\n CodeBlockTabs,\n CodeBlockTabsList,\n CodeBlockTabsTrigger,\n} from 'fumadocs-ui/components/codeblock';\nimport { UsageTabsSelectorLazy, UsageTabLazy } from './lazy';\nimport { ResponseTabs } from '../response-tabs';\nimport { registerDefault } from '@/requests/generators/all';\n\n/**\n * Generate code example for given programming language\n */\nexport interface CodeUsageGenerator<T = unknown> {\n id: string;\n lang: string;\n label?: string;\n /**\n * either:\n * - code\n * - a function imported from a file with \"use client\" directive\n * - false (disabled)\n */\n source?: string | CodeUsageGeneratorFn<T> | false;\n\n /**\n * Pass extra context to client-side source generator\n */\n serverContext?: T;\n}\n\nexport async function UsageTabs({\n method,\n ctx,\n}: {\n method: MethodInformation;\n ctx: RenderContext;\n}) {\n let { renderAPIExampleUsageTabs, renderAPIExampleLayout } = ctx.content ?? {};\n\n renderAPIExampleLayout ??= (slots) => {\n return (\n <div className=\"prose-no-margin\">\n {slots.selector}\n {slots.usageTabs}\n {slots.responseTabs}\n </div>\n );\n };\n\n renderAPIExampleUsageTabs ??= (registry) => {\n const map = Array.from(registry.map().entries());\n if (map.length === 0) return null;\n\n return (\n <CodeBlockTabs groupId=\"fumadocs_openapi_requests\" defaultValue={map[0][0]}>\n <CodeBlockTabsList>\n {map.map(([id, item]) => (\n <CodeBlockTabsTrigger key={id} value={id}>\n {item.label ?? item.lang}\n </CodeBlockTabsTrigger>\n ))}\n </CodeBlockTabsList>\n {map.map(([id, item]) => (\n <CodeBlockTab key={id} value={id}>\n <UsageTabLazy id={id} lang={item.lang} _client={item._client} />\n </CodeBlockTab>\n ))}\n </CodeBlockTabs>\n );\n };\n\n let registry: CodeUsageGeneratorRegistry;\n if (ctx.codeUsages) {\n registry = createCodeUsageGeneratorRegistry(ctx.codeUsages);\n } else {\n registry = createCodeUsageGeneratorRegistry();\n registerDefault(registry);\n }\n\n for (const gen of (await ctx.generateCodeSamples?.(method)) ?? []) {\n registry.addInline(gen);\n }\n\n if (method['x-codeSamples']) {\n for (const sample of method['x-codeSamples']) {\n registry.addInline(sample);\n }\n }\n\n return renderAPIExampleLayout(\n {\n selector: method['x-exclusiveCodeSample'] ? null : <UsageTabsSelectorLazy />,\n usageTabs: await renderAPIExampleUsageTabs(registry, ctx),\n responseTabs: <ResponseTabs operation={method} ctx={ctx} />,\n },\n ctx,\n );\n}\n"],"mappings":";;;;;;;AAqCA,eAAsB,UAAU,EAC9B,QACA,OAIC;CACD,IAAI,EAAE,2BAA2B,2BAA2B,IAAI,WAAW,EAAE;AAE7E,6BAA4B,UAAU;AACpC,SACE,qBAAC,OAAD;GAAK,WAAU;aAAf;IACG,MAAM;IACN,MAAM;IACN,MAAM;IACH;;;AAIV,gCAA+B,aAAa;EAC1C,MAAM,MAAM,MAAM,KAAK,SAAS,KAAK,CAAC,SAAS,CAAC;AAChD,MAAI,IAAI,WAAW,EAAG,QAAO;AAE7B,SACE,qBAAC,eAAD;GAAe,SAAQ;GAA4B,cAAc,IAAI,GAAG;aAAxE,CACE,oBAAC,mBAAD,EAAA,UACG,IAAI,KAAK,CAAC,IAAI,UACb,oBAAC,sBAAD;IAA+B,OAAO;cACnC,KAAK,SAAS,KAAK;IACC,EAFI,GAEJ,CACvB,EACgB,CAAA,EACnB,IAAI,KAAK,CAAC,IAAI,UACb,oBAAC,cAAD;IAAuB,OAAO;cAC5B,oBAAC,cAAD;KAAkB;KAAI,MAAM,KAAK;KAAM,SAAS,KAAK;KAAW,CAAA;IACnD,EAFI,GAEJ,CACf,CACY;;;CAIpB,IAAI;AACJ,KAAI,IAAI,WACN,YAAW,iCAAiC,IAAI,WAAW;MACtD;AACL,aAAW,kCAAkC;AAC7C,kBAAgB,SAAS;;AAG3B,MAAK,MAAM,OAAQ,MAAM,IAAI,sBAAsB,OAAO,IAAK,EAAE,CAC/D,UAAS,UAAU,IAAI;AAGzB,KAAI,OAAO,iBACT,MAAK,MAAM,UAAU,OAAO,iBAC1B,UAAS,UAAU,OAAO;AAI9B,QAAO,uBACL;EACE,UAAU,OAAO,2BAA2B,OAAO,oBAAC,uBAAD,EAAyB,CAAA;EAC5E,WAAW,MAAM,0BAA0B,UAAU,IAAI;EACzD,cAAc,oBAAC,cAAD;GAAc,WAAW;GAAa;GAAO,CAAA;EAC5D,EACD,IACD"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/ui/operation/usage-tabs/index.tsx"],"sourcesContent":["import type { MethodInformation, RenderContext } from '@/types';\nimport {\n type CodeUsageGeneratorRegistry,\n createCodeUsageGeneratorRegistry,\n} from '@/requests/generators';\nimport {\n CodeBlockTab,\n CodeBlockTabs,\n CodeBlockTabsList,\n CodeBlockTabsTrigger,\n} from 'fumadocs-ui/components/codeblock';\nimport { UsageTabsSelectorLazy, UsageTabLazy } from './lazy';\nimport { ResponseTabs } from '../response-tabs';\nimport { registerDefault } from '@/requests/generators/all';\nimport { useMemo } from 'react';\n\nexport function UsageTabs({ method, ctx }: { method: MethodInformation; ctx: RenderContext }) {\n let { renderAPIExampleUsageTabs, renderAPIExampleLayout } = ctx.content ?? {};\n\n renderAPIExampleLayout ??= (slots) => {\n return (\n <div className=\"prose-no-margin\">\n {slots.selector}\n {slots.usageTabs}\n {slots.responseTabs}\n </div>\n );\n };\n\n renderAPIExampleUsageTabs ??= (registry) => {\n const map = Array.from(registry.map().entries());\n if (map.length === 0) return null;\n\n return (\n <CodeBlockTabs groupId=\"fumadocs_openapi_requests\" defaultValue={map[0][0]}>\n <CodeBlockTabsList>\n {map.map(([id, item]) => (\n <CodeBlockTabsTrigger key={id} value={id}>\n {item.label ?? item.lang}\n </CodeBlockTabsTrigger>\n ))}\n </CodeBlockTabsList>\n {map.map(([id, item]) => (\n <CodeBlockTab key={id} value={id}>\n <UsageTabLazy id={id} lang={item.lang} _client={item._client} />\n </CodeBlockTab>\n ))}\n </CodeBlockTabs>\n );\n };\n\n const registry = useMemo(() => {\n let registry: CodeUsageGeneratorRegistry;\n\n if (ctx.codeUsages) {\n registry = createCodeUsageGeneratorRegistry(ctx.codeUsages);\n } else {\n registry = createCodeUsageGeneratorRegistry();\n registerDefault(registry);\n }\n\n for (const gen of ctx.generateCodeSamples?.(method) ?? []) {\n registry.addInline(gen);\n }\n\n if (method['x-codeSamples']) {\n for (const sample of method['x-codeSamples']) {\n registry.addInline(sample);\n }\n }\n\n return registry;\n }, [ctx, method]);\n\n return renderAPIExampleLayout(\n {\n selector: method['x-exclusiveCodeSample'] ? null : <UsageTabsSelectorLazy />,\n usageTabs: renderAPIExampleUsageTabs(registry, ctx),\n responseTabs: <ResponseTabs operation={method} ctx={ctx} />,\n },\n ctx,\n );\n}\n"],"mappings":";;;;;;;;AAgBA,SAAgB,UAAU,EAAE,QAAQ,OAA0D;CAC5F,IAAI,EAAE,2BAA2B,2BAA2B,IAAI,WAAW,EAAE;AAE7E,6BAA4B,UAAU;AACpC,SACE,qBAAC,OAAD;GAAK,WAAU;aAAf;IACG,MAAM;IACN,MAAM;IACN,MAAM;IACH;;;AAIV,gCAA+B,aAAa;EAC1C,MAAM,MAAM,MAAM,KAAK,SAAS,KAAK,CAAC,SAAS,CAAC;AAChD,MAAI,IAAI,WAAW,EAAG,QAAO;AAE7B,SACE,qBAAC,eAAD;GAAe,SAAQ;GAA4B,cAAc,IAAI,GAAG;aAAxE,CACE,oBAAC,mBAAD,EAAA,UACG,IAAI,KAAK,CAAC,IAAI,UACb,oBAAC,sBAAD;IAA+B,OAAO;cACnC,KAAK,SAAS,KAAK;IACC,EAFI,GAEJ,CACvB,EACgB,CAAA,EACnB,IAAI,KAAK,CAAC,IAAI,UACb,oBAAC,cAAD;IAAuB,OAAO;cAC5B,oBAAC,cAAD;KAAkB;KAAI,MAAM,KAAK;KAAM,SAAS,KAAK;KAAW,CAAA;IACnD,EAFI,GAEJ,CACf,CACY;;;CAIpB,MAAM,WAAW,cAAc;EAC7B,IAAI;AAEJ,MAAI,IAAI,WACN,YAAW,iCAAiC,IAAI,WAAW;OACtD;AACL,cAAW,kCAAkC;AAC7C,mBAAgB,SAAS;;AAG3B,OAAK,MAAM,OAAO,IAAI,sBAAsB,OAAO,IAAI,EAAE,CACvD,UAAS,UAAU,IAAI;AAGzB,MAAI,OAAO,iBACT,MAAK,MAAM,UAAU,OAAO,iBAC1B,UAAS,UAAU,OAAO;AAI9B,SAAO;IACN,CAAC,KAAK,OAAO,CAAC;AAEjB,QAAO,uBACL;EACE,UAAU,OAAO,2BAA2B,OAAO,oBAAC,uBAAD,EAAyB,CAAA;EAC5E,WAAW,0BAA0B,UAAU,IAAI;EACnD,cAAc,oBAAC,cAAD;GAAc,WAAW;GAAa;GAAO,CAAA;EAC5D,EACD,IACD"}
@@ -3,8 +3,7 @@ import { wrapLazy } from "../../../utils/lazy.js";
3
3
  //#region src/ui/operation/usage-tabs/lazy.tsx
4
4
  const UsageTabsSelectorLazy = wrapLazy(() => import("./client.js").then((mod) => ({ default: mod.UsageTabsSelector })));
5
5
  const UsageTabLazy = wrapLazy(() => import("./client.js").then((mod) => ({ default: mod.UsageTab })));
6
- const UsageTabsProviderLazy = wrapLazy(() => import("./client.js").then((mod) => ({ default: mod.UsageTabsProvider })));
7
6
  //#endregion
8
- export { UsageTabLazy, UsageTabsProviderLazy, UsageTabsSelectorLazy };
7
+ export { UsageTabLazy, UsageTabsSelectorLazy };
9
8
 
10
9
  //# sourceMappingURL=lazy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"lazy.js","names":[],"sources":["../../../../src/ui/operation/usage-tabs/lazy.tsx"],"sourcesContent":["'use client';\nimport { wrapLazy } from '../../../utils/lazy';\n\nexport const UsageTabsSelectorLazy = wrapLazy(() =>\n import('./client').then((mod) => ({ default: mod.UsageTabsSelector })),\n);\n\nexport const UsageTabLazy = wrapLazy(() =>\n import('./client').then((mod) => ({ default: mod.UsageTab })),\n);\n\nexport const UsageTabsProviderLazy = wrapLazy(() =>\n import('./client').then((mod) => ({ default: mod.UsageTabsProvider })),\n);\n"],"mappings":";;;AAGA,MAAa,wBAAwB,eACnC,OAAO,eAAY,MAAM,SAAS,EAAE,SAAS,IAAI,mBAAmB,EAAE,CACvE;AAED,MAAa,eAAe,eAC1B,OAAO,eAAY,MAAM,SAAS,EAAE,SAAS,IAAI,UAAU,EAAE,CAC9D;AAED,MAAa,wBAAwB,eACnC,OAAO,eAAY,MAAM,SAAS,EAAE,SAAS,IAAI,mBAAmB,EAAE,CACvE"}
1
+ {"version":3,"file":"lazy.js","names":[],"sources":["../../../../src/ui/operation/usage-tabs/lazy.tsx"],"sourcesContent":["'use client';\nimport { wrapLazy } from '../../../utils/lazy';\n\nexport const UsageTabsSelectorLazy = wrapLazy(() =>\n import('./client').then((mod) => ({ default: mod.UsageTabsSelector })),\n);\n\nexport const UsageTabLazy = wrapLazy(() =>\n import('./client').then((mod) => ({ default: mod.UsageTab })),\n);\n"],"mappings":";;;AAGA,MAAa,wBAAwB,eACnC,OAAO,eAAY,MAAM,SAAS,EAAE,SAAS,IAAI,mBAAmB,EAAE,CACvE;AAED,MAAa,eAAe,eAC1B,OAAO,eAAY,MAAM,SAAS,EAAE,SAAS,IAAI,UAAU,EAAE,CAC9D"}
@@ -1,4 +1,4 @@
1
- import { ResolvedSchema } from "../../utils/schema.js";
1
+ import { ResolvedSchema } from "../../utils/schema/index.js";
2
2
  import { SchemaUIProps } from "./client.js";
3
3
  import { ReactNode } from "react";
4
4
 
@@ -1,14 +1,16 @@
1
1
  import { mergeAllOf } from "../../utils/merge-schema.js";
2
- import { FormatFlags, schemaToString } from "../../utils/schema-to-string.js";
2
+ import { FormatFlags, schemaToString } from "../../utils/schema/to-string.js";
3
3
  import { I18nLabel } from "../client/i18n.js";
4
4
  import { SchemaUILazy } from "./lazy.js";
5
+ import { useMemo } from "react";
5
6
  import { jsx } from "react/jsx-runtime";
6
7
  //#region src/ui/schema/index.tsx
7
8
  function Schema({ ctx, ...options }) {
8
9
  if (ctx.schemaUI?.render) return ctx.schemaUI.render(options, ctx);
10
+ const generated = useMemo(() => generateSchemaUI(options, ctx), [ctx, options]);
9
11
  return /* @__PURE__ */ jsx(SchemaUILazy, {
10
12
  ...options.client,
11
- generated: generateSchemaUI(options, ctx)
13
+ generated
12
14
  });
13
15
  }
14
16
  function generateSchemaUI({ root, readOnly, writeOnly }, ctx) {