zudoku 0.26.1 → 0.27.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 (214) hide show
  1. package/dist/app/main.d.ts +1 -1
  2. package/dist/app/main.js +19 -7
  3. package/dist/app/main.js.map +1 -1
  4. package/dist/config/loader.js +1 -1
  5. package/dist/config/loader.js.map +1 -1
  6. package/dist/config/validators/InputSidebarSchema.d.ts +2 -2
  7. package/dist/config/validators/common.d.ts +67 -0
  8. package/dist/config/validators/common.js +5 -0
  9. package/dist/config/validators/common.js.map +1 -1
  10. package/dist/config/validators/validate.d.ts +29 -0
  11. package/dist/lib/components/AnchorLink.js +5 -2
  12. package/dist/lib/components/AnchorLink.js.map +1 -1
  13. package/dist/lib/components/Header.js +1 -1
  14. package/dist/lib/components/Header.js.map +1 -1
  15. package/dist/lib/components/Heading.d.ts +1 -1
  16. package/dist/lib/components/Markdown.d.ts +2 -2
  17. package/dist/lib/components/Markdown.js +3 -1
  18. package/dist/lib/components/Markdown.js.map +1 -1
  19. package/dist/lib/components/StatusPage.d.ts +7 -0
  20. package/dist/lib/components/StatusPage.js +71 -0
  21. package/dist/lib/components/StatusPage.js.map +1 -0
  22. package/dist/lib/components/SyntaxHighlight.d.ts +2 -1
  23. package/dist/lib/components/SyntaxHighlight.js +2 -2
  24. package/dist/lib/components/SyntaxHighlight.js.map +1 -1
  25. package/dist/lib/components/ThemeSwitch.js +4 -4
  26. package/dist/lib/components/ThemeSwitch.js.map +1 -1
  27. package/dist/lib/components/cache.d.ts +6 -0
  28. package/dist/lib/components/cache.js +13 -0
  29. package/dist/lib/components/cache.js.map +1 -0
  30. package/dist/lib/components/context/ViewportAnchorContext.js +16 -4
  31. package/dist/lib/components/context/ViewportAnchorContext.js.map +1 -1
  32. package/dist/lib/components/context/ZudokuContext.js +2 -1
  33. package/dist/lib/components/context/ZudokuContext.js.map +1 -1
  34. package/dist/lib/components/index.d.ts +9 -2
  35. package/dist/lib/components/index.js +3 -0
  36. package/dist/lib/components/index.js.map +1 -1
  37. package/dist/lib/core/RouteGuard.d.ts +1 -0
  38. package/dist/lib/core/RouteGuard.js +28 -0
  39. package/dist/lib/core/RouteGuard.js.map +1 -0
  40. package/dist/lib/core/ZudokuContext.d.ts +4 -2
  41. package/dist/lib/core/ZudokuContext.js +9 -7
  42. package/dist/lib/core/ZudokuContext.js.map +1 -1
  43. package/dist/lib/oas/graphql/circular.d.ts +3 -0
  44. package/dist/lib/oas/graphql/circular.js +27 -0
  45. package/dist/lib/oas/graphql/circular.js.map +1 -0
  46. package/dist/lib/oas/graphql/index.js +5 -6
  47. package/dist/lib/oas/graphql/index.js.map +1 -1
  48. package/dist/lib/oas/parser/dereference/index.d.ts +0 -1
  49. package/dist/lib/oas/parser/dereference/index.js +1 -1
  50. package/dist/lib/oas/parser/dereference/index.js.map +1 -1
  51. package/dist/lib/plugins/openapi/OperationListItem.js +1 -1
  52. package/dist/lib/plugins/openapi/OperationListItem.js.map +1 -1
  53. package/dist/lib/plugins/openapi/ParameterListItem.js +1 -1
  54. package/dist/lib/plugins/openapi/ParameterListItem.js.map +1 -1
  55. package/dist/lib/plugins/openapi/Sidecar.js +2 -2
  56. package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
  57. package/dist/lib/plugins/openapi/index.js +4 -11
  58. package/dist/lib/plugins/openapi/index.js.map +1 -1
  59. package/dist/lib/plugins/openapi/interfaces.d.ts +7 -2
  60. package/dist/lib/plugins/openapi/playground/ExamplesDropdown.js +5 -5
  61. package/dist/lib/plugins/openapi/playground/ExamplesDropdown.js.map +1 -1
  62. package/dist/lib/plugins/openapi/playground/Headers.js +17 -16
  63. package/dist/lib/plugins/openapi/playground/Headers.js.map +1 -1
  64. package/dist/lib/plugins/openapi/playground/ParamsGrid.d.ts +5 -0
  65. package/dist/lib/plugins/openapi/playground/ParamsGrid.js +4 -0
  66. package/dist/lib/plugins/openapi/playground/ParamsGrid.js.map +1 -0
  67. package/dist/lib/plugins/openapi/playground/PathParams.js +4 -12
  68. package/dist/lib/plugins/openapi/playground/PathParams.js.map +1 -1
  69. package/dist/lib/plugins/openapi/playground/Playground.d.ts +13 -0
  70. package/dist/lib/plugins/openapi/playground/Playground.js +19 -31
  71. package/dist/lib/plugins/openapi/playground/Playground.js.map +1 -1
  72. package/dist/lib/plugins/openapi/playground/PlaygroundDialog.js +1 -1
  73. package/dist/lib/plugins/openapi/playground/PlaygroundDialog.js.map +1 -1
  74. package/dist/lib/plugins/openapi/playground/QueryParams.js +4 -3
  75. package/dist/lib/plugins/openapi/playground/QueryParams.js.map +1 -1
  76. package/dist/lib/plugins/openapi/playground/SubmitButton.d.ts +7 -0
  77. package/dist/lib/plugins/openapi/playground/SubmitButton.js +22 -0
  78. package/dist/lib/plugins/openapi/playground/SubmitButton.js.map +1 -0
  79. package/dist/lib/plugins/openapi/playground/result-panel/RequestTab.d.ts +7 -0
  80. package/dist/lib/plugins/openapi/playground/result-panel/RequestTab.js +11 -0
  81. package/dist/lib/plugins/openapi/playground/result-panel/RequestTab.js.map +1 -0
  82. package/dist/lib/plugins/openapi/playground/result-panel/ResponseTab.d.ts +8 -0
  83. package/dist/lib/plugins/openapi/playground/result-panel/ResponseTab.js +95 -0
  84. package/dist/lib/plugins/openapi/playground/result-panel/ResponseTab.js.map +1 -0
  85. package/dist/lib/plugins/openapi/playground/result-panel/ResultPanel.d.ts +7 -0
  86. package/dist/lib/plugins/openapi/playground/result-panel/ResultPanel.js +16 -0
  87. package/dist/lib/plugins/openapi/playground/result-panel/ResultPanel.js.map +1 -0
  88. package/dist/lib/plugins/openapi/playground/result-panel/convertToTypes.d.ts +10 -0
  89. package/dist/lib/plugins/openapi/playground/result-panel/convertToTypes.js +32 -0
  90. package/dist/lib/plugins/openapi/playground/result-panel/convertToTypes.js.map +1 -0
  91. package/dist/lib/plugins/openapi/playground/result-panel/convertToTypes.test.d.ts +1 -0
  92. package/dist/lib/plugins/openapi/playground/result-panel/convertToTypes.test.js +56 -0
  93. package/dist/lib/plugins/openapi/playground/result-panel/convertToTypes.test.js.map +1 -0
  94. package/dist/lib/plugins/openapi/schema/SchemaComponents.js +1 -1
  95. package/dist/lib/plugins/openapi/schema/SchemaComponents.js.map +1 -1
  96. package/dist/lib/ui/Command.js +1 -1
  97. package/dist/lib/ui/Command.js.map +1 -1
  98. package/dist/lib/ui/Select.js +2 -2
  99. package/dist/lib/ui/Select.js.map +1 -1
  100. package/dist/lib/util/MdxComponents.js +2 -2
  101. package/dist/lib/util/MdxComponents.js.map +1 -1
  102. package/dist/lib/util/useScrollToAnchor.d.ts +1 -0
  103. package/dist/lib/util/useScrollToAnchor.js +26 -15
  104. package/dist/lib/util/useScrollToAnchor.js.map +1 -1
  105. package/dist/vite/plugin-api.js +9 -3
  106. package/dist/vite/plugin-api.js.map +1 -1
  107. package/dist/vite/prerender.js +1 -0
  108. package/dist/vite/prerender.js.map +1 -1
  109. package/dist/zuplo/enrich-with-zuplo.js +1 -1
  110. package/dist/zuplo/enrich-with-zuplo.js.map +1 -1
  111. package/dist/zuplo/with-zuplo.d.ts +2 -1
  112. package/dist/zuplo/with-zuplo.js +3 -1
  113. package/dist/zuplo/with-zuplo.js.map +1 -1
  114. package/lib/{AuthenticationPlugin-C9SwOxkc.js → AuthenticationPlugin-CO_YCd2x.js} +3 -3
  115. package/lib/{AuthenticationPlugin-C9SwOxkc.js.map → AuthenticationPlugin-CO_YCd2x.js.map} +1 -1
  116. package/lib/{Markdown-DFN6p0J-.js → Markdown-B8o9Qz4q.js} +1197 -1186
  117. package/lib/{Markdown-DFN6p0J-.js.map → Markdown-B8o9Qz4q.js.map} +1 -1
  118. package/lib/{MdxPage-D9c4z09Q.js → MdxPage-BxRt3Ly7.js} +5 -5
  119. package/lib/{MdxPage-D9c4z09Q.js.map → MdxPage-BxRt3Ly7.js.map} +1 -1
  120. package/lib/OperationList-DH-zIgtq.js +5160 -0
  121. package/lib/OperationList-DH-zIgtq.js.map +1 -0
  122. package/lib/{Route-VdmEyOD0.js → Route-DJ0ZlVq1.js} +3 -3
  123. package/lib/{Route-VdmEyOD0.js.map → Route-DJ0ZlVq1.js.map} +1 -1
  124. package/lib/{Select-D3O7wISy.js → Select-B7UXR0SB.js} +61 -61
  125. package/lib/Select-B7UXR0SB.js.map +1 -0
  126. package/lib/{SlotletProvider-_3zzX_g_.js → SlotletProvider-CtIp8rP3.js} +4 -4
  127. package/lib/{SlotletProvider-_3zzX_g_.js.map → SlotletProvider-CtIp8rP3.js.map} +1 -1
  128. package/lib/{SyntaxHighlight-CJCSPG1F.js → SyntaxHighlight-C1w1QPdY.js} +300 -295
  129. package/lib/{SyntaxHighlight-CJCSPG1F.js.map → SyntaxHighlight-C1w1QPdY.js.map} +1 -1
  130. package/lib/{ZudokuContext-DeQZEp-x.js → ZudokuContext-8jts0fF3.js} +259 -248
  131. package/lib/ZudokuContext-8jts0fF3.js.map +1 -0
  132. package/lib/{chunk-SYFQ2XB5-BF5IDYrB.js → chunk-SYFQ2XB5-BPvC-soB.js} +5 -5
  133. package/lib/{chunk-SYFQ2XB5-BF5IDYrB.js.map → chunk-SYFQ2XB5-BPvC-soB.js.map} +1 -1
  134. package/lib/circular-Dgpd6AN-.js +15397 -0
  135. package/lib/circular-Dgpd6AN-.js.map +1 -0
  136. package/lib/{createServer-BcaswoFO.js → createServer-BV0tHzLK.js} +3450 -5577
  137. package/lib/createServer-BV0tHzLK.js.map +1 -0
  138. package/lib/{hook-BRQEDRbn.js → hook-BG02esyv.js} +2 -2
  139. package/lib/{hook-BRQEDRbn.js.map → hook-BG02esyv.js.map} +1 -1
  140. package/lib/index-DmqsUPcm.js +1915 -0
  141. package/lib/index-DmqsUPcm.js.map +1 -0
  142. package/lib/ui/Command.js +27 -27
  143. package/lib/ui/Command.js.map +1 -1
  144. package/lib/ui/Select.js +2 -2
  145. package/lib/ui/Select.js.map +1 -1
  146. package/lib/{useExposedProps-CetwhZpP.js → useExposedProps-BLKFBylA.js} +2 -2
  147. package/lib/{useExposedProps-CetwhZpP.js.map → useExposedProps-BLKFBylA.js.map} +1 -1
  148. package/lib/useScrollToAnchor-Bl6mz9_x.js +288 -0
  149. package/lib/useScrollToAnchor-Bl6mz9_x.js.map +1 -0
  150. package/lib/zudoku.auth-clerk.js +1 -1
  151. package/lib/zudoku.auth-openid.js +3 -3
  152. package/lib/zudoku.components.js +753 -991
  153. package/lib/zudoku.components.js.map +1 -1
  154. package/lib/zudoku.plugin-api-catalog.js +3 -3
  155. package/lib/zudoku.plugin-api-keys.js +5 -5
  156. package/lib/zudoku.plugin-custom-pages.js +2 -2
  157. package/lib/zudoku.plugin-markdown.js +1 -1
  158. package/lib/zudoku.plugin-openapi.js +4 -4
  159. package/lib/zudoku.plugin-redirect.js +1 -1
  160. package/package.json +2 -2
  161. package/src/app/main.tsx +26 -7
  162. package/src/lib/components/AnchorLink.tsx +5 -2
  163. package/src/lib/components/Header.tsx +1 -1
  164. package/src/lib/components/Markdown.tsx +14 -15
  165. package/src/lib/components/StatusPage.tsx +91 -0
  166. package/src/lib/components/SyntaxHighlight.tsx +14 -0
  167. package/src/lib/components/ThemeSwitch.tsx +14 -15
  168. package/src/lib/components/cache.ts +15 -0
  169. package/src/lib/components/context/ViewportAnchorContext.tsx +20 -6
  170. package/src/lib/components/context/ZudokuContext.ts +3 -1
  171. package/src/lib/components/index.ts +7 -0
  172. package/src/lib/core/RouteGuard.tsx +35 -0
  173. package/src/lib/core/ZudokuContext.ts +9 -8
  174. package/src/lib/oas/graphql/circular.ts +29 -0
  175. package/src/lib/oas/graphql/index.ts +9 -9
  176. package/src/lib/oas/parser/dereference/index.ts +1 -2
  177. package/src/lib/plugins/openapi/OperationListItem.tsx +0 -2
  178. package/src/lib/plugins/openapi/ParameterListItem.tsx +1 -0
  179. package/src/lib/plugins/openapi/Sidecar.tsx +3 -2
  180. package/src/lib/plugins/openapi/index.tsx +9 -15
  181. package/src/lib/plugins/openapi/interfaces.ts +10 -2
  182. package/src/lib/plugins/openapi/playground/ExamplesDropdown.tsx +30 -27
  183. package/src/lib/plugins/openapi/playground/Headers.tsx +65 -65
  184. package/src/lib/plugins/openapi/playground/ParamsGrid.tsx +8 -0
  185. package/src/lib/plugins/openapi/playground/PathParams.tsx +34 -74
  186. package/src/lib/plugins/openapi/playground/Playground.tsx +64 -116
  187. package/src/lib/plugins/openapi/playground/PlaygroundDialog.tsx +1 -1
  188. package/src/lib/plugins/openapi/playground/QueryParams.tsx +46 -45
  189. package/src/lib/plugins/openapi/playground/SubmitButton.tsx +75 -0
  190. package/src/lib/plugins/openapi/playground/result-panel/RequestTab.tsx +73 -0
  191. package/src/lib/plugins/openapi/playground/result-panel/ResponseTab.tsx +210 -0
  192. package/src/lib/plugins/openapi/playground/result-panel/ResultPanel.tsx +101 -0
  193. package/src/lib/plugins/openapi/playground/result-panel/convertToTypes.test.ts +64 -0
  194. package/src/lib/plugins/openapi/playground/result-panel/convertToTypes.ts +36 -0
  195. package/src/lib/plugins/openapi/schema/SchemaComponents.tsx +1 -1
  196. package/src/lib/ui/Command.tsx +1 -1
  197. package/src/lib/ui/Select.tsx +1 -1
  198. package/src/lib/util/MdxComponents.tsx +2 -1
  199. package/src/lib/util/useScrollToAnchor.ts +32 -15
  200. package/dist/lib/plugins/openapi/playground/ResponseTab.d.ts +0 -4
  201. package/dist/lib/plugins/openapi/playground/ResponseTab.js +0 -42
  202. package/dist/lib/plugins/openapi/playground/ResponseTab.js.map +0 -1
  203. package/lib/AnchorLink-bObQitZv.js +0 -34
  204. package/lib/AnchorLink-bObQitZv.js.map +0 -1
  205. package/lib/OperationList-DGJWDx1G.js +0 -5148
  206. package/lib/OperationList-DGJWDx1G.js.map +0 -1
  207. package/lib/Select-D3O7wISy.js.map +0 -1
  208. package/lib/ZudokuContext-DeQZEp-x.js.map +0 -1
  209. package/lib/createServer-BcaswoFO.js.map +0 -1
  210. package/lib/index-CXRrqOIl.js +0 -1750
  211. package/lib/index-CXRrqOIl.js.map +0 -1
  212. package/lib/index-TaRXY2w1.js +0 -43
  213. package/lib/index-TaRXY2w1.js.map +0 -1
  214. package/src/lib/plugins/openapi/playground/ResponseTab.tsx +0 -76
@@ -1,16 +1,15 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  import SchemaBuilder from "@pothos/core";
3
3
  import {
4
- slugifyWithCounter,
5
4
  type CountableSlugify,
5
+ slugifyWithCounter,
6
6
  } from "@sindresorhus/slugify";
7
7
  import { GraphQLJSON, GraphQLJSONObject } from "graphql-type-json";
8
8
  import { createYoga, type YogaServerOptions } from "graphql-yoga";
9
9
  import {
10
- HttpMethods,
11
- validate,
12
10
  type EncodingObject,
13
11
  type ExampleObject,
12
+ HttpMethods,
14
13
  type OpenAPIDocument,
15
14
  type OperationObject,
16
15
  type ParameterObject,
@@ -18,7 +17,9 @@ import {
18
17
  type SchemaObject,
19
18
  type ServerObject,
20
19
  type TagObject,
20
+ validate,
21
21
  } from "../parser/index.js";
22
+ import { GraphQLJSONSchema } from "./circular.js";
22
23
 
23
24
  export type {
24
25
  EncodingObject,
@@ -45,10 +46,7 @@ export const createOperationSlug = (
45
46
  ) => {
46
47
  const summary =
47
48
  (operation.summary ?? "") +
48
- (operation.operationId
49
- ? "-" +
50
- operation.operationId.slice(0, operation.summary ? Infinity : Infinity)
51
- : "");
49
+ (operation.operationId ? "-" + operation.operationId : "");
52
50
 
53
51
  return slugify(
54
52
  (tag ? tag + "-" : "") +
@@ -65,6 +63,7 @@ const builder = new SchemaBuilder<{
65
63
  Scalars: {
66
64
  JSON: any;
67
65
  JSONObject: any;
66
+ JSONSchema: any;
68
67
  };
69
68
  Context: {
70
69
  schema: OpenAPIDocument;
@@ -74,6 +73,7 @@ const builder = new SchemaBuilder<{
74
73
 
75
74
  const JSONScalar = builder.addScalarType("JSON", GraphQLJSON);
76
75
  const JSONObjectScalar = builder.addScalarType("JSONObject", GraphQLJSONObject);
76
+ const JSONSchemaScalar = builder.addScalarType("JSONSchema", GraphQLJSONSchema);
77
77
 
78
78
  const getAllTags = (schema: OpenAPIDocument): TagObject[] => {
79
79
  const tags = schema.tags ?? [];
@@ -238,7 +238,7 @@ const ParameterItem = builder
238
238
  })),
239
239
  nullable: true,
240
240
  }),
241
- schema: t.expose("schema", { type: JSONScalar, nullable: true }),
241
+ schema: t.expose("schema", { type: JSONSchemaScalar, nullable: true }),
242
242
  }),
243
243
  });
244
244
 
@@ -252,7 +252,7 @@ const MediaTypeItem = builder
252
252
  .implement({
253
253
  fields: (t) => ({
254
254
  mediaType: t.exposeString("mediaType"),
255
- schema: t.expose("schema", { type: JSONScalar, nullable: true }),
255
+ schema: t.expose("schema", { type: JSONSchemaScalar, nullable: true }),
256
256
  examples: t.expose("examples", { type: [ExampleItem], nullable: true }),
257
257
  encoding: t.expose("encoding", { type: [EncodingItem], nullable: true }),
258
258
  }),
@@ -1,10 +1,9 @@
1
1
  import type { JSONSchema4, JSONSchema6 } from "json-schema";
2
+ import { CIRCULAR_REF } from "../../graphql/circular.js";
2
3
  import { resolveLocalRef } from "./resolveRef.js";
3
4
 
4
5
  export type JSONSchema = JSONSchema4 | JSONSchema6;
5
6
 
6
- export const CIRCULAR_REF = "$[Circular Reference]";
7
-
8
7
  type CustomResolver = (ref: string) => Promise<JSONSchema | undefined>;
9
8
 
10
9
  const cache = new Map<JSONSchema, JSONSchema>();
@@ -95,7 +95,6 @@ export const OperationListItem = ({
95
95
  level={3}
96
96
  className="capitalize"
97
97
  id={`${operation.slug}/request-body`}
98
- registerSidebarAnchor
99
98
  >
100
99
  Request Body
101
100
  </Heading>
@@ -108,7 +107,6 @@ export const OperationListItem = ({
108
107
  level={3}
109
108
  className="capitalize mt-8 pt-8 border-t"
110
109
  id={`${operation.slug}/responses`}
111
- registerSidebarAnchor
112
110
  >
113
111
  Responses
114
112
  </Heading>
@@ -54,6 +54,7 @@ export const ParameterListItem = ({
54
54
  </Badge>
55
55
  )}
56
56
  {parameter.required && <Badge variant="outline">required</Badge>}
57
+ {parameter.style === "form" && <Badge variant="secondary">form</Badge>}
57
58
  </div>
58
59
  {parameter.description && (
59
60
  <Markdown
@@ -99,7 +99,7 @@ export const Sidecar = ({
99
99
  selectedResponse?: string;
100
100
  onSelectResponse: (response: string) => void;
101
101
  }) => {
102
- const { input, type } = useOasConfig();
102
+ const { input, type, options } = useOasConfig();
103
103
  const query = useCreateQuery(GetServerQuery, { input, type });
104
104
  const result = useSuspenseQuery(query);
105
105
 
@@ -109,7 +109,8 @@ export const Sidecar = ({
109
109
  const [, startTransition] = useTransition();
110
110
  const [selectedExample, setSelectedExample] = useState<unknown>();
111
111
 
112
- const selectedLang = searchParams.get("lang") ?? "shell";
112
+ const selectedLang =
113
+ searchParams.get("lang") ?? options?.examplesDefaultLanguage ?? "shell";
113
114
 
114
115
  const requestBodyContent = operation.requestBody?.content;
115
116
 
@@ -2,7 +2,6 @@ import { matchPath } from "react-router";
2
2
  import { type ZudokuPlugin } from "../../core/plugins.js";
3
3
  import { graphql } from "./graphql/index.js";
4
4
 
5
- import { useQuery } from "@tanstack/react-query";
6
5
  import { CirclePlayIcon, LogInIcon } from "lucide-react";
7
6
  import type { SidebarItem } from "../../../config/validators/SidebarSchema.js";
8
7
  import { useAuth } from "../../authentication/hook.js";
@@ -81,18 +80,15 @@ export const openApiPlugin = (config: OpenApiPluginOptions): ZudokuPlugin => {
81
80
  method,
82
81
  url,
83
82
  ...props
84
- }: Partial<PlaygroundContentProps> & { requireAuth: boolean }) => {
83
+ }: Partial<PlaygroundContentProps> &
84
+ Pick<PlaygroundContentProps, "server"> & {
85
+ requireAuth: boolean;
86
+ }) => {
85
87
  const auth = useAuth();
86
- // We don't have the GraphQL context here
87
- const serverQuery = useQuery({
88
- queryFn: () =>
89
- client.fetch(GetCategoriesQuery, {
90
- type: config.type,
91
- input: config.input,
92
- }),
93
- enabled: !server,
94
- queryKey: ["playground-server"],
95
- });
88
+
89
+ if (!server) {
90
+ throw new Error("Server is required");
91
+ }
96
92
 
97
93
  if (requireAuth && !auth.isAuthenticated) {
98
94
  return (
@@ -110,9 +106,7 @@ export const openApiPlugin = (config: OpenApiPluginOptions): ZudokuPlugin => {
110
106
  <PlaygroundDialog
111
107
  url={url ?? "/"}
112
108
  method={method ?? "get"}
113
- server={
114
- server ?? serverQuery.data?.schema.url ?? "https://example.com"
115
- }
109
+ server={server}
116
110
  {...props}
117
111
  >
118
112
  <Button className="gap-2 items-center" variant="outline">
@@ -20,7 +20,14 @@ export type OasPluginConfig = {
20
20
  server?: string;
21
21
  navigationId?: string;
22
22
  skipPreload?: boolean;
23
- } & OasSource;
23
+ } & OasPluginConfigOptions &
24
+ OasSource;
25
+
26
+ export type OasPluginConfigOptions = {
27
+ options?: {
28
+ examplesDefaultLanguage?: string;
29
+ };
30
+ };
24
31
 
25
32
  export type OasPluginContext = {
26
33
  server?: string;
@@ -28,4 +35,5 @@ export type OasPluginContext = {
28
35
  skipPreload?: boolean;
29
36
  version?: string;
30
37
  versions: Record<string, string>;
31
- } & ContextOasSource;
38
+ } & ContextOasSource &
39
+ OasPluginConfigOptions;
@@ -18,33 +18,36 @@ const ExamplesDropdown = ({
18
18
  onSelect: (example: Example) => void;
19
19
  }) => {
20
20
  return (
21
- <DropdownMenu>
22
- <DropdownMenuTrigger asChild>
23
- <Button variant="outline">Use Example</Button>
24
- </DropdownMenuTrigger>
25
- <DropdownMenuContent className="w-56">
26
- {examples.map((example) => {
27
- return (
28
- <div key={example.mediaType}>
29
- <DropdownMenuLabel>{example.mediaType}</DropdownMenuLabel>
30
- <DropdownMenuSeparator />
31
- <DropdownMenuGroup>
32
- {example.examples?.map((example) => {
33
- return (
34
- <DropdownMenuItem
35
- key={example.name}
36
- onSelect={() => onSelect(example)}
37
- >
38
- {example.name}
39
- </DropdownMenuItem>
40
- );
41
- })}
42
- </DropdownMenuGroup>
43
- </div>
44
- );
45
- })}
46
- </DropdownMenuContent>
47
- </DropdownMenu>
21
+ <div className="flex flex-col gap-2 mt-2 items-end">
22
+ <DropdownMenu>
23
+ <DropdownMenuTrigger asChild>
24
+ <Button variant="outline">Use Example</Button>
25
+ </DropdownMenuTrigger>
26
+ <DropdownMenuContent className="w-56">
27
+ {examples.map((example) => {
28
+ return (
29
+ <div key={example.mediaType}>
30
+ <DropdownMenuLabel>{example.mediaType}</DropdownMenuLabel>
31
+ <DropdownMenuSeparator />
32
+ <DropdownMenuGroup>
33
+ {example.examples?.map((example) => {
34
+ return (
35
+ <DropdownMenuItem
36
+ key={example.name}
37
+ onSelect={() => onSelect(example)}
38
+ className="line-clamp-1"
39
+ >
40
+ {example.summary ?? example.name}
41
+ </DropdownMenuItem>
42
+ );
43
+ })}
44
+ </DropdownMenuGroup>
45
+ </div>
46
+ );
47
+ })}
48
+ </DropdownMenuContent>
49
+ </DropdownMenu>
50
+ </div>
48
51
  );
49
52
  };
50
53
 
@@ -12,6 +12,7 @@ import { Checkbox } from "zudoku/ui/Checkbox.js";
12
12
  import { Autocomplete } from "../../../components/Autocomplete.js";
13
13
  import { Button } from "../../../ui/Button.js";
14
14
  import { Input } from "../../../ui/Input.js";
15
+ import ParamsGrid from "./ParamsGrid.js";
15
16
  import { type PlaygroundForm } from "./Playground.js";
16
17
 
17
18
  const headerOptions = Object.freeze([
@@ -77,56 +78,55 @@ export const Headers = ({
77
78
 
78
79
  return (
79
80
  <div className="flex flex-col gap-2">
80
- <Card className="flex flex-col gap-2 overflow-hidden">
81
- <table className="w-full">
82
- <tbody>
83
- {fields.map((header, i) => (
84
- <tr
85
- key={header.id}
86
- className="group has-[:focus]:bg-muted/50 hover:bg-muted/50"
87
- >
88
- <td className="flex gap-2 items-center pl-3">
89
- <Controller
90
- control={control}
91
- name={`headers.${i}.active`}
92
- render={({ field }) => (
93
- <Checkbox
94
- variant="outline"
95
- id={`headers.${i}.active`}
96
- checked={field.value}
97
- onCheckedChange={(checked) => {
98
- field.onChange(checked);
99
- }}
100
- />
101
- )}
102
- />
103
- <Controller
104
- control={control}
105
- name={`headers.${i}.name`}
106
- render={({ field }) => (
107
- <Autocomplete
108
- {...field}
109
- placeholder="Name"
110
- className="border-0 shadow-none bg-transparent text-xs font-mono"
111
- options={headerOptions}
112
- onEnterPress={() => handleHeaderEnter(i)}
113
- onChange={(e) => {
114
- field.onChange(e);
115
- setValue(`headers.${i}.active`, true);
116
- }}
117
- ref={(el) => {
118
- nameRefs.current[i] = el;
119
- }}
120
- />
121
- )}
122
- />
123
- </td>
124
- <td>
125
- <div className="flex items-center gap-2">
81
+ <Card className="overflow-hidden">
82
+ <ParamsGrid>
83
+ {fields.map((header, i) => (
84
+ <div key={i} className="group grid col-span-full grid-cols-subgrid">
85
+ <div className="flex items-center gap-2 ">
86
+ <Controller
87
+ control={control}
88
+ name={`headers.${i}.active`}
89
+ render={({ field }) => (
90
+ <Checkbox
91
+ variant="outline"
92
+ id={`headers.${i}.active`}
93
+ checked={field.value}
94
+ onCheckedChange={(checked) => {
95
+ field.onChange(checked);
96
+ }}
97
+ />
98
+ )}
99
+ />
100
+ <Controller
101
+ control={control}
102
+ name={`headers.${i}.name`}
103
+ render={({ field }) => (
104
+ <Autocomplete
105
+ {...field}
106
+ placeholder="Name"
107
+ className="border-0 shadow-none bg-transparent text-xs font-mono"
108
+ options={headerOptions}
109
+ onEnterPress={() => handleHeaderEnter(i)}
110
+ onChange={(e) => {
111
+ field.onChange(e);
112
+ setValue(`headers.${i}.active`, true);
113
+ }}
114
+ ref={(el) => {
115
+ nameRefs.current[i] = el;
116
+ }}
117
+ />
118
+ )}
119
+ />
120
+ </div>
121
+ <div className="flex items-center gap-2">
122
+ <Controller
123
+ control={control}
124
+ name={`headers.${i}.value`}
125
+ render={({ field }) => (
126
126
  <Input
127
127
  placeholder="Value"
128
- className="w-full border-0 shadow-none text-xs font-mono"
129
- {...register(`headers.${i}.value`)}
128
+ className="w-full border-0 shadow-none text-xs font-mono focus-visible:ring-0"
129
+ {...field}
130
130
  ref={(el) => {
131
131
  valueRefs.current[i] = el;
132
132
  }}
@@ -137,23 +137,23 @@ export const Headers = ({
137
137
  }}
138
138
  autoComplete="off"
139
139
  />
140
- <Button
141
- size="icon"
142
- variant="ghost"
143
- className="text-muted-foreground opacity-0 group-hover:opacity-100"
144
- onClick={() => {
145
- remove(i);
146
- }}
147
- type="button"
148
- >
149
- <XIcon size={16} />
150
- </Button>
151
- </div>
152
- </td>
153
- </tr>
154
- ))}
155
- </tbody>
156
- </table>
140
+ )}
141
+ />
142
+ <Button
143
+ size="icon"
144
+ variant="ghost"
145
+ className="text-muted-foreground opacity-0 group-hover:opacity-100 rounded-full w-8 h-7"
146
+ onClick={() => {
147
+ remove(i);
148
+ }}
149
+ type="button"
150
+ >
151
+ <XIcon size={16} />
152
+ </Button>
153
+ </div>
154
+ </div>
155
+ ))}
156
+ </ParamsGrid>
157
157
  </Card>
158
158
  <div className="text-end">
159
159
  <Button
@@ -0,0 +1,8 @@
1
+ import createVariantComponent from "../../../util/createVariantComponent.js";
2
+
3
+ const ParamsGrid = createVariantComponent(
4
+ "div",
5
+ "hover:bg-accent/40 grid grid-cols-[2fr_3fr] gap-2 items-center px-3",
6
+ );
7
+
8
+ export default ParamsGrid;
@@ -1,31 +1,10 @@
1
- import { EraserIcon } from "lucide-react";
2
1
  import { Control, Controller, useFieldArray } from "react-hook-form";
3
2
  import { Card } from "zudoku/ui/Card.js";
4
- import { Button } from "../../../ui/Button.js";
5
3
  import { Input } from "../../../ui/Input.js";
6
- import { cn } from "../../../util/cn.js";
7
- import { ColorizedParam, useParamColor } from "../ColorizedParam.js";
4
+ import { ColorizedParam } from "../ColorizedParam.js";
5
+ import ParamsGrid from "./ParamsGrid.js";
8
6
  import type { PlaygroundForm } from "./Playground.js";
9
7
 
10
- const PathParamLabel = ({ name }: { name: string }) => {
11
- const color = useParamColor(name);
12
-
13
- return (
14
- <div className="flex items-center">
15
- <div
16
- className="w-2 h-2 rounded-full"
17
- style={{ backgroundColor: `hsl(${color})` }}
18
- />
19
-
20
- <ColorizedParam
21
- slug={name}
22
- name={name}
23
- className="font-mono text-xs m-2 px-1"
24
- />
25
- </div>
26
- );
27
- };
28
-
29
8
  export const PathParams = ({
30
9
  control,
31
10
  }: {
@@ -38,59 +17,40 @@ export const PathParams = ({
38
17
 
39
18
  return (
40
19
  <Card className="rounded-lg">
41
- <table className="w-full">
42
- <tbody>
43
- {fields.map((part, i) => (
44
- <tr key={part.id} className="hover:bg-accent/40">
45
- <td className="w-5/12">
46
- <Controller
47
- control={control}
48
- name={`pathParams.${i}.value`}
49
- render={() => <PathParamLabel name={part.name} />}
50
- />
51
- </td>
52
- <td className="w-7/12">
53
- <div className="flex justify-between items-center">
54
- <Controller
55
- control={control}
56
- name={`pathParams.${i}.value`}
57
- render={({ field }) => (
58
- <Input
59
- {...field}
60
- required
61
- placeholder="Enter value"
62
- className="w-full border-0 shadow-none text-xs font-mono hover:bg-accent"
63
- />
64
- )}
65
- />
66
- <Controller
67
- control={control}
68
- name={`pathParams.${i}.value`}
69
- render={({ field }) => (
70
- <Button
71
- size="icon"
72
- type="button"
73
- variant="ghost"
74
- aria-label="Clear value"
75
- className={cn(
76
- "ms-2 mr-1",
77
- field.value.length === 0
78
- ? "opacity-0 pointer-events-none"
79
- : "opacity-100",
80
- )}
81
- title="Clear value"
82
- onClick={() => field.onChange("")}
83
- >
84
- <EraserIcon size={16} />
85
- </Button>
86
- )}
20
+ <ParamsGrid>
21
+ {fields.map((part, i) => (
22
+ <>
23
+ <Controller
24
+ control={control}
25
+ name={`pathParams.${i}.value`}
26
+ render={() => (
27
+ <div>
28
+ <ColorizedParam
29
+ slug={part.name}
30
+ name={part.name}
31
+ className="font-mono text-xs px-2"
87
32
  />
88
33
  </div>
89
- </td>
90
- </tr>
91
- ))}
92
- </tbody>
93
- </table>
34
+ )}
35
+ />
36
+
37
+ <div className="flex justify-between items-center">
38
+ <Controller
39
+ control={control}
40
+ name={`pathParams.${i}.value`}
41
+ render={({ field }) => (
42
+ <Input
43
+ {...field}
44
+ required
45
+ placeholder="Enter value"
46
+ className="w-full border-0 shadow-none text-xs font-mono hover:bg-accent"
47
+ />
48
+ )}
49
+ />
50
+ </div>
51
+ </>
52
+ ))}
53
+ </ParamsGrid>
94
54
  </Card>
95
55
  );
96
56
  };