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.
- package/dist/app/main.d.ts +1 -1
- package/dist/app/main.js +19 -7
- package/dist/app/main.js.map +1 -1
- package/dist/config/loader.js +1 -1
- package/dist/config/loader.js.map +1 -1
- package/dist/config/validators/InputSidebarSchema.d.ts +2 -2
- package/dist/config/validators/common.d.ts +67 -0
- package/dist/config/validators/common.js +5 -0
- package/dist/config/validators/common.js.map +1 -1
- package/dist/config/validators/validate.d.ts +29 -0
- package/dist/lib/components/AnchorLink.js +5 -2
- package/dist/lib/components/AnchorLink.js.map +1 -1
- package/dist/lib/components/Header.js +1 -1
- package/dist/lib/components/Header.js.map +1 -1
- package/dist/lib/components/Heading.d.ts +1 -1
- package/dist/lib/components/Markdown.d.ts +2 -2
- package/dist/lib/components/Markdown.js +3 -1
- package/dist/lib/components/Markdown.js.map +1 -1
- package/dist/lib/components/StatusPage.d.ts +7 -0
- package/dist/lib/components/StatusPage.js +71 -0
- package/dist/lib/components/StatusPage.js.map +1 -0
- package/dist/lib/components/SyntaxHighlight.d.ts +2 -1
- package/dist/lib/components/SyntaxHighlight.js +2 -2
- package/dist/lib/components/SyntaxHighlight.js.map +1 -1
- package/dist/lib/components/ThemeSwitch.js +4 -4
- package/dist/lib/components/ThemeSwitch.js.map +1 -1
- package/dist/lib/components/cache.d.ts +6 -0
- package/dist/lib/components/cache.js +13 -0
- package/dist/lib/components/cache.js.map +1 -0
- package/dist/lib/components/context/ViewportAnchorContext.js +16 -4
- package/dist/lib/components/context/ViewportAnchorContext.js.map +1 -1
- package/dist/lib/components/context/ZudokuContext.js +2 -1
- package/dist/lib/components/context/ZudokuContext.js.map +1 -1
- package/dist/lib/components/index.d.ts +9 -2
- package/dist/lib/components/index.js +3 -0
- package/dist/lib/components/index.js.map +1 -1
- package/dist/lib/core/RouteGuard.d.ts +1 -0
- package/dist/lib/core/RouteGuard.js +28 -0
- package/dist/lib/core/RouteGuard.js.map +1 -0
- package/dist/lib/core/ZudokuContext.d.ts +4 -2
- package/dist/lib/core/ZudokuContext.js +9 -7
- package/dist/lib/core/ZudokuContext.js.map +1 -1
- package/dist/lib/oas/graphql/circular.d.ts +3 -0
- package/dist/lib/oas/graphql/circular.js +27 -0
- package/dist/lib/oas/graphql/circular.js.map +1 -0
- package/dist/lib/oas/graphql/index.js +5 -6
- package/dist/lib/oas/graphql/index.js.map +1 -1
- package/dist/lib/oas/parser/dereference/index.d.ts +0 -1
- package/dist/lib/oas/parser/dereference/index.js +1 -1
- package/dist/lib/oas/parser/dereference/index.js.map +1 -1
- package/dist/lib/plugins/openapi/OperationListItem.js +1 -1
- package/dist/lib/plugins/openapi/OperationListItem.js.map +1 -1
- package/dist/lib/plugins/openapi/ParameterListItem.js +1 -1
- package/dist/lib/plugins/openapi/ParameterListItem.js.map +1 -1
- package/dist/lib/plugins/openapi/Sidecar.js +2 -2
- package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
- package/dist/lib/plugins/openapi/index.js +4 -11
- package/dist/lib/plugins/openapi/index.js.map +1 -1
- package/dist/lib/plugins/openapi/interfaces.d.ts +7 -2
- package/dist/lib/plugins/openapi/playground/ExamplesDropdown.js +5 -5
- package/dist/lib/plugins/openapi/playground/ExamplesDropdown.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/Headers.js +17 -16
- package/dist/lib/plugins/openapi/playground/Headers.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/ParamsGrid.d.ts +5 -0
- package/dist/lib/plugins/openapi/playground/ParamsGrid.js +4 -0
- package/dist/lib/plugins/openapi/playground/ParamsGrid.js.map +1 -0
- package/dist/lib/plugins/openapi/playground/PathParams.js +4 -12
- package/dist/lib/plugins/openapi/playground/PathParams.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/Playground.d.ts +13 -0
- package/dist/lib/plugins/openapi/playground/Playground.js +19 -31
- package/dist/lib/plugins/openapi/playground/Playground.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/PlaygroundDialog.js +1 -1
- package/dist/lib/plugins/openapi/playground/PlaygroundDialog.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/QueryParams.js +4 -3
- package/dist/lib/plugins/openapi/playground/QueryParams.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/SubmitButton.d.ts +7 -0
- package/dist/lib/plugins/openapi/playground/SubmitButton.js +22 -0
- package/dist/lib/plugins/openapi/playground/SubmitButton.js.map +1 -0
- package/dist/lib/plugins/openapi/playground/result-panel/RequestTab.d.ts +7 -0
- package/dist/lib/plugins/openapi/playground/result-panel/RequestTab.js +11 -0
- package/dist/lib/plugins/openapi/playground/result-panel/RequestTab.js.map +1 -0
- package/dist/lib/plugins/openapi/playground/result-panel/ResponseTab.d.ts +8 -0
- package/dist/lib/plugins/openapi/playground/result-panel/ResponseTab.js +95 -0
- package/dist/lib/plugins/openapi/playground/result-panel/ResponseTab.js.map +1 -0
- package/dist/lib/plugins/openapi/playground/result-panel/ResultPanel.d.ts +7 -0
- package/dist/lib/plugins/openapi/playground/result-panel/ResultPanel.js +16 -0
- package/dist/lib/plugins/openapi/playground/result-panel/ResultPanel.js.map +1 -0
- package/dist/lib/plugins/openapi/playground/result-panel/convertToTypes.d.ts +10 -0
- package/dist/lib/plugins/openapi/playground/result-panel/convertToTypes.js +32 -0
- package/dist/lib/plugins/openapi/playground/result-panel/convertToTypes.js.map +1 -0
- package/dist/lib/plugins/openapi/playground/result-panel/convertToTypes.test.d.ts +1 -0
- package/dist/lib/plugins/openapi/playground/result-panel/convertToTypes.test.js +56 -0
- package/dist/lib/plugins/openapi/playground/result-panel/convertToTypes.test.js.map +1 -0
- package/dist/lib/plugins/openapi/schema/SchemaComponents.js +1 -1
- package/dist/lib/plugins/openapi/schema/SchemaComponents.js.map +1 -1
- package/dist/lib/ui/Command.js +1 -1
- package/dist/lib/ui/Command.js.map +1 -1
- package/dist/lib/ui/Select.js +2 -2
- package/dist/lib/ui/Select.js.map +1 -1
- package/dist/lib/util/MdxComponents.js +2 -2
- package/dist/lib/util/MdxComponents.js.map +1 -1
- package/dist/lib/util/useScrollToAnchor.d.ts +1 -0
- package/dist/lib/util/useScrollToAnchor.js +26 -15
- package/dist/lib/util/useScrollToAnchor.js.map +1 -1
- package/dist/vite/plugin-api.js +9 -3
- package/dist/vite/plugin-api.js.map +1 -1
- package/dist/vite/prerender.js +1 -0
- package/dist/vite/prerender.js.map +1 -1
- package/dist/zuplo/enrich-with-zuplo.js +1 -1
- package/dist/zuplo/enrich-with-zuplo.js.map +1 -1
- package/dist/zuplo/with-zuplo.d.ts +2 -1
- package/dist/zuplo/with-zuplo.js +3 -1
- package/dist/zuplo/with-zuplo.js.map +1 -1
- package/lib/{AuthenticationPlugin-C9SwOxkc.js → AuthenticationPlugin-CO_YCd2x.js} +3 -3
- package/lib/{AuthenticationPlugin-C9SwOxkc.js.map → AuthenticationPlugin-CO_YCd2x.js.map} +1 -1
- package/lib/{Markdown-DFN6p0J-.js → Markdown-B8o9Qz4q.js} +1197 -1186
- package/lib/{Markdown-DFN6p0J-.js.map → Markdown-B8o9Qz4q.js.map} +1 -1
- package/lib/{MdxPage-D9c4z09Q.js → MdxPage-BxRt3Ly7.js} +5 -5
- package/lib/{MdxPage-D9c4z09Q.js.map → MdxPage-BxRt3Ly7.js.map} +1 -1
- package/lib/OperationList-DH-zIgtq.js +5160 -0
- package/lib/OperationList-DH-zIgtq.js.map +1 -0
- package/lib/{Route-VdmEyOD0.js → Route-DJ0ZlVq1.js} +3 -3
- package/lib/{Route-VdmEyOD0.js.map → Route-DJ0ZlVq1.js.map} +1 -1
- package/lib/{Select-D3O7wISy.js → Select-B7UXR0SB.js} +61 -61
- package/lib/Select-B7UXR0SB.js.map +1 -0
- package/lib/{SlotletProvider-_3zzX_g_.js → SlotletProvider-CtIp8rP3.js} +4 -4
- package/lib/{SlotletProvider-_3zzX_g_.js.map → SlotletProvider-CtIp8rP3.js.map} +1 -1
- package/lib/{SyntaxHighlight-CJCSPG1F.js → SyntaxHighlight-C1w1QPdY.js} +300 -295
- package/lib/{SyntaxHighlight-CJCSPG1F.js.map → SyntaxHighlight-C1w1QPdY.js.map} +1 -1
- package/lib/{ZudokuContext-DeQZEp-x.js → ZudokuContext-8jts0fF3.js} +259 -248
- package/lib/ZudokuContext-8jts0fF3.js.map +1 -0
- package/lib/{chunk-SYFQ2XB5-BF5IDYrB.js → chunk-SYFQ2XB5-BPvC-soB.js} +5 -5
- package/lib/{chunk-SYFQ2XB5-BF5IDYrB.js.map → chunk-SYFQ2XB5-BPvC-soB.js.map} +1 -1
- package/lib/circular-Dgpd6AN-.js +15397 -0
- package/lib/circular-Dgpd6AN-.js.map +1 -0
- package/lib/{createServer-BcaswoFO.js → createServer-BV0tHzLK.js} +3450 -5577
- package/lib/createServer-BV0tHzLK.js.map +1 -0
- package/lib/{hook-BRQEDRbn.js → hook-BG02esyv.js} +2 -2
- package/lib/{hook-BRQEDRbn.js.map → hook-BG02esyv.js.map} +1 -1
- package/lib/index-DmqsUPcm.js +1915 -0
- package/lib/index-DmqsUPcm.js.map +1 -0
- package/lib/ui/Command.js +27 -27
- package/lib/ui/Command.js.map +1 -1
- package/lib/ui/Select.js +2 -2
- package/lib/ui/Select.js.map +1 -1
- package/lib/{useExposedProps-CetwhZpP.js → useExposedProps-BLKFBylA.js} +2 -2
- package/lib/{useExposedProps-CetwhZpP.js.map → useExposedProps-BLKFBylA.js.map} +1 -1
- package/lib/useScrollToAnchor-Bl6mz9_x.js +288 -0
- package/lib/useScrollToAnchor-Bl6mz9_x.js.map +1 -0
- package/lib/zudoku.auth-clerk.js +1 -1
- package/lib/zudoku.auth-openid.js +3 -3
- package/lib/zudoku.components.js +753 -991
- package/lib/zudoku.components.js.map +1 -1
- package/lib/zudoku.plugin-api-catalog.js +3 -3
- package/lib/zudoku.plugin-api-keys.js +5 -5
- package/lib/zudoku.plugin-custom-pages.js +2 -2
- package/lib/zudoku.plugin-markdown.js +1 -1
- package/lib/zudoku.plugin-openapi.js +4 -4
- package/lib/zudoku.plugin-redirect.js +1 -1
- package/package.json +2 -2
- package/src/app/main.tsx +26 -7
- package/src/lib/components/AnchorLink.tsx +5 -2
- package/src/lib/components/Header.tsx +1 -1
- package/src/lib/components/Markdown.tsx +14 -15
- package/src/lib/components/StatusPage.tsx +91 -0
- package/src/lib/components/SyntaxHighlight.tsx +14 -0
- package/src/lib/components/ThemeSwitch.tsx +14 -15
- package/src/lib/components/cache.ts +15 -0
- package/src/lib/components/context/ViewportAnchorContext.tsx +20 -6
- package/src/lib/components/context/ZudokuContext.ts +3 -1
- package/src/lib/components/index.ts +7 -0
- package/src/lib/core/RouteGuard.tsx +35 -0
- package/src/lib/core/ZudokuContext.ts +9 -8
- package/src/lib/oas/graphql/circular.ts +29 -0
- package/src/lib/oas/graphql/index.ts +9 -9
- package/src/lib/oas/parser/dereference/index.ts +1 -2
- package/src/lib/plugins/openapi/OperationListItem.tsx +0 -2
- package/src/lib/plugins/openapi/ParameterListItem.tsx +1 -0
- package/src/lib/plugins/openapi/Sidecar.tsx +3 -2
- package/src/lib/plugins/openapi/index.tsx +9 -15
- package/src/lib/plugins/openapi/interfaces.ts +10 -2
- package/src/lib/plugins/openapi/playground/ExamplesDropdown.tsx +30 -27
- package/src/lib/plugins/openapi/playground/Headers.tsx +65 -65
- package/src/lib/plugins/openapi/playground/ParamsGrid.tsx +8 -0
- package/src/lib/plugins/openapi/playground/PathParams.tsx +34 -74
- package/src/lib/plugins/openapi/playground/Playground.tsx +64 -116
- package/src/lib/plugins/openapi/playground/PlaygroundDialog.tsx +1 -1
- package/src/lib/plugins/openapi/playground/QueryParams.tsx +46 -45
- package/src/lib/plugins/openapi/playground/SubmitButton.tsx +75 -0
- package/src/lib/plugins/openapi/playground/result-panel/RequestTab.tsx +73 -0
- package/src/lib/plugins/openapi/playground/result-panel/ResponseTab.tsx +210 -0
- package/src/lib/plugins/openapi/playground/result-panel/ResultPanel.tsx +101 -0
- package/src/lib/plugins/openapi/playground/result-panel/convertToTypes.test.ts +64 -0
- package/src/lib/plugins/openapi/playground/result-panel/convertToTypes.ts +36 -0
- package/src/lib/plugins/openapi/schema/SchemaComponents.tsx +1 -1
- package/src/lib/ui/Command.tsx +1 -1
- package/src/lib/ui/Select.tsx +1 -1
- package/src/lib/util/MdxComponents.tsx +2 -1
- package/src/lib/util/useScrollToAnchor.ts +32 -15
- package/dist/lib/plugins/openapi/playground/ResponseTab.d.ts +0 -4
- package/dist/lib/plugins/openapi/playground/ResponseTab.js +0 -42
- package/dist/lib/plugins/openapi/playground/ResponseTab.js.map +0 -1
- package/lib/AnchorLink-bObQitZv.js +0 -34
- package/lib/AnchorLink-bObQitZv.js.map +0 -1
- package/lib/OperationList-DGJWDx1G.js +0 -5148
- package/lib/OperationList-DGJWDx1G.js.map +0 -1
- package/lib/Select-D3O7wISy.js.map +0 -1
- package/lib/ZudokuContext-DeQZEp-x.js.map +0 -1
- package/lib/createServer-BcaswoFO.js.map +0 -1
- package/lib/index-CXRrqOIl.js +0 -1750
- package/lib/index-CXRrqOIl.js.map +0 -1
- package/lib/index-TaRXY2w1.js +0 -43
- package/lib/index-TaRXY2w1.js.map +0 -1
- package/src/lib/plugins/openapi/playground/ResponseTab.tsx +0 -76
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { useQuery } from "@tanstack/react-query";
|
|
2
|
+
import { ChevronRightIcon } from "lucide-react";
|
|
3
|
+
import { Fragment, useState } from "react";
|
|
4
|
+
import {
|
|
5
|
+
Collapsible,
|
|
6
|
+
CollapsibleContent,
|
|
7
|
+
CollapsibleTrigger,
|
|
8
|
+
} from "zudoku/ui/Collapsible.js";
|
|
9
|
+
import {
|
|
10
|
+
Select,
|
|
11
|
+
SelectContent,
|
|
12
|
+
SelectItem,
|
|
13
|
+
SelectTrigger,
|
|
14
|
+
SelectValue,
|
|
15
|
+
} from "zudoku/ui/Select.js";
|
|
16
|
+
import { SyntaxHighlight } from "../../../../components/SyntaxHighlight.js";
|
|
17
|
+
import { Card } from "../../../../ui/Card.js";
|
|
18
|
+
import { convertToTypes } from "./convertToTypes.js";
|
|
19
|
+
|
|
20
|
+
const statusCodeMap: Record<number, string> = {
|
|
21
|
+
200: "OK",
|
|
22
|
+
201: "Created",
|
|
23
|
+
202: "Accepted",
|
|
24
|
+
204: "No Content",
|
|
25
|
+
400: "Bad Request",
|
|
26
|
+
401: "Unauthorized",
|
|
27
|
+
403: "Forbidden",
|
|
28
|
+
404: "Not Found",
|
|
29
|
+
405: "Method Not Allowed",
|
|
30
|
+
500: "Internal Server Error",
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const mimeTypeToLanguage = (mimeType: string) => {
|
|
34
|
+
const mimeTypeMapping = {
|
|
35
|
+
"application/json": "json",
|
|
36
|
+
"text/json": "json",
|
|
37
|
+
"text/html": "html",
|
|
38
|
+
"text/css": "css",
|
|
39
|
+
"text/javascript": "javascript",
|
|
40
|
+
"application/xml": "xml",
|
|
41
|
+
"application/xhtml+xml": "xhtml",
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return Object.entries(mimeTypeMapping).find(([mime]) =>
|
|
45
|
+
mimeType.includes(mime),
|
|
46
|
+
)?.[1];
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const detectLanguage = (headers: Array<[string, string]>) => {
|
|
50
|
+
const contentType =
|
|
51
|
+
headers.find(([key, value]) => key === "Content-Type")?.[1] || "";
|
|
52
|
+
return mimeTypeToLanguage(contentType);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const tryParseJson = (body: string) => {
|
|
56
|
+
try {
|
|
57
|
+
return JSON.stringify(JSON.parse(body), null, 2);
|
|
58
|
+
} catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const sortHeadersByRelevance = (
|
|
64
|
+
headers: Array<[string, string]>,
|
|
65
|
+
): Array<[string, string]> => {
|
|
66
|
+
const priorityOrder = [
|
|
67
|
+
"Content-Type",
|
|
68
|
+
"Content-Length",
|
|
69
|
+
"Authorization",
|
|
70
|
+
"X-RateLimit-Remaining",
|
|
71
|
+
"X-RateLimit-Limit",
|
|
72
|
+
"Cache-Control",
|
|
73
|
+
"ETag",
|
|
74
|
+
].map((key) => key.toLowerCase());
|
|
75
|
+
|
|
76
|
+
return [...headers].sort(([keyA], [keyB]) => {
|
|
77
|
+
const indexA = priorityOrder.indexOf(keyA.toLowerCase());
|
|
78
|
+
const indexB = priorityOrder.indexOf(keyB.toLowerCase());
|
|
79
|
+
if (indexA === indexB) return 0;
|
|
80
|
+
if (indexA === -1) return 1;
|
|
81
|
+
if (indexB === -1) return -1;
|
|
82
|
+
return indexA - indexB;
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export const ResponseTab = ({
|
|
87
|
+
body = "",
|
|
88
|
+
headers,
|
|
89
|
+
status,
|
|
90
|
+
time,
|
|
91
|
+
size,
|
|
92
|
+
url,
|
|
93
|
+
}: {
|
|
94
|
+
body?: string;
|
|
95
|
+
headers: Array<[string, string]>;
|
|
96
|
+
status: number;
|
|
97
|
+
time: number;
|
|
98
|
+
size: number;
|
|
99
|
+
url: string;
|
|
100
|
+
}) => {
|
|
101
|
+
const detectedLanguage = detectLanguage(headers);
|
|
102
|
+
const jsonContent = tryParseJson(body);
|
|
103
|
+
const beautifiedBody = jsonContent || body;
|
|
104
|
+
const [view, setView] = useState<"formatted" | "raw" | "types">(
|
|
105
|
+
jsonContent ? "formatted" : "raw",
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
const types = useQuery({
|
|
109
|
+
queryKey: ["types", beautifiedBody],
|
|
110
|
+
queryFn: async () => {
|
|
111
|
+
return convertToTypes(JSON.parse(beautifiedBody));
|
|
112
|
+
},
|
|
113
|
+
enabled: view === "types",
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const sortedHeaders = sortHeadersByRelevance([...headers]);
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<div className="flex flex-col gap-2 h-full overflow-y-scroll max-h-[calc(100vh-220px)] py-4">
|
|
120
|
+
<Collapsible defaultOpen>
|
|
121
|
+
<CollapsibleTrigger className="flex items-center gap-2 hover:text-primary group">
|
|
122
|
+
<ChevronRightIcon className="h-4 w-4 transition-transform duration-200 group-data-[state=open]:rotate-[90deg]" />
|
|
123
|
+
<span className="font-semibold">Headers</span>
|
|
124
|
+
</CollapsibleTrigger>
|
|
125
|
+
<CollapsibleContent>
|
|
126
|
+
<div className="grid grid-cols-[auto,1fr] gap-x-8 gap-y-1 pl-1.5 pt-2 font-mono text-xs">
|
|
127
|
+
{sortedHeaders.slice(0, 5).map(([key, value]) => (
|
|
128
|
+
<Fragment key={key}>
|
|
129
|
+
<div className="text-primary whitespace-pre">{key}</div>
|
|
130
|
+
<div className="break-all">{value}</div>
|
|
131
|
+
</Fragment>
|
|
132
|
+
))}
|
|
133
|
+
{sortedHeaders.length > 5 && (
|
|
134
|
+
<Collapsible className="col-span-full grid-cols-subgrid grid">
|
|
135
|
+
<CollapsibleTrigger className="col-span-2 text-xs text-muted-foreground hover:text-primary flex items-center gap-1 py-1">
|
|
136
|
+
<ChevronRightIcon className="h-3 w-3 transition-transform duration-200 group-data-[state=open]:rotate-[90deg]" />
|
|
137
|
+
Show {sortedHeaders.length - 5} more headers
|
|
138
|
+
</CollapsibleTrigger>
|
|
139
|
+
<CollapsibleContent className="col-span-full grid grid-cols-subgrid gap-x-8 gap-y-1 ">
|
|
140
|
+
{sortedHeaders.slice(5).map(([key, value]) => (
|
|
141
|
+
<Fragment key={key}>
|
|
142
|
+
<div className="text-primary whitespace-pre">{key}</div>
|
|
143
|
+
<div className="break-all">{value}</div>
|
|
144
|
+
</Fragment>
|
|
145
|
+
))}
|
|
146
|
+
</CollapsibleContent>
|
|
147
|
+
</Collapsible>
|
|
148
|
+
)}
|
|
149
|
+
</div>
|
|
150
|
+
</CollapsibleContent>
|
|
151
|
+
</Collapsible>
|
|
152
|
+
|
|
153
|
+
<Card className="shadow-none">
|
|
154
|
+
<SyntaxHighlight
|
|
155
|
+
language={
|
|
156
|
+
view === "types"
|
|
157
|
+
? "typescript"
|
|
158
|
+
: view === "raw"
|
|
159
|
+
? jsonContent
|
|
160
|
+
? "plain"
|
|
161
|
+
: detectedLanguage
|
|
162
|
+
: "json"
|
|
163
|
+
}
|
|
164
|
+
noBackground
|
|
165
|
+
// playground dialog has h-5/6 ≈ 83.333vh
|
|
166
|
+
className="overflow-x-auto p-4 text-xs max-h-[calc(83.333vh-180px)]"
|
|
167
|
+
code={
|
|
168
|
+
(view === "raw"
|
|
169
|
+
? body
|
|
170
|
+
: view === "types"
|
|
171
|
+
? types.data?.lines.join("\n")
|
|
172
|
+
: beautifiedBody) ?? ""
|
|
173
|
+
}
|
|
174
|
+
/>
|
|
175
|
+
</Card>
|
|
176
|
+
<div className="flex gap-2 justify-between">
|
|
177
|
+
<div className="flex text-xs gap-2 border bg-muted rounded-md p-2 items-center h-8 font-mono divide-x">
|
|
178
|
+
<div>
|
|
179
|
+
<span className="text-muted-foreground">Status</span> {status}{" "}
|
|
180
|
+
{statusCodeMap[status] ?? ""}
|
|
181
|
+
</div>
|
|
182
|
+
<div>
|
|
183
|
+
<span className="text-muted-foreground">Time</span>{" "}
|
|
184
|
+
{time.toFixed(0)}ms
|
|
185
|
+
</div>
|
|
186
|
+
<div>
|
|
187
|
+
<span className="text-muted-foreground">Size</span> {size}B
|
|
188
|
+
</div>
|
|
189
|
+
</div>
|
|
190
|
+
{jsonContent && (
|
|
191
|
+
<div>
|
|
192
|
+
<Select
|
|
193
|
+
value={view}
|
|
194
|
+
onValueChange={(value) => setView(value as "formatted" | "raw")}
|
|
195
|
+
>
|
|
196
|
+
<SelectTrigger className="min-w-32">
|
|
197
|
+
<SelectValue placeholder="View" />
|
|
198
|
+
</SelectTrigger>
|
|
199
|
+
<SelectContent>
|
|
200
|
+
<SelectItem value="formatted">Formatted</SelectItem>
|
|
201
|
+
<SelectItem value="raw">Raw</SelectItem>
|
|
202
|
+
<SelectItem value="types">Types</SelectItem>
|
|
203
|
+
</SelectContent>
|
|
204
|
+
</Select>
|
|
205
|
+
</div>
|
|
206
|
+
)}
|
|
207
|
+
</div>
|
|
208
|
+
</div>
|
|
209
|
+
);
|
|
210
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { UseMutationResult } from "@tanstack/react-query";
|
|
2
|
+
import { Spinner } from "../../../../components/Spinner.js";
|
|
3
|
+
import { Callout } from "../../../../ui/Callout.js";
|
|
4
|
+
import {
|
|
5
|
+
Card,
|
|
6
|
+
CardContent,
|
|
7
|
+
CardHeader,
|
|
8
|
+
CardTitle,
|
|
9
|
+
} from "../../../../ui/Card.js";
|
|
10
|
+
import {
|
|
11
|
+
Tabs,
|
|
12
|
+
TabsContent,
|
|
13
|
+
TabsList,
|
|
14
|
+
TabsTrigger,
|
|
15
|
+
} from "../../../../ui/Tabs.js";
|
|
16
|
+
import { cn } from "../../../../util/cn.js";
|
|
17
|
+
import { PlaygroundResult } from "../Playground.js";
|
|
18
|
+
import { RequestTab } from "./RequestTab.js";
|
|
19
|
+
import { ResponseTab } from "./ResponseTab.js";
|
|
20
|
+
|
|
21
|
+
export const ResultPanel = ({
|
|
22
|
+
queryMutation,
|
|
23
|
+
showPathParamsWarning,
|
|
24
|
+
}: {
|
|
25
|
+
queryMutation: UseMutationResult<PlaygroundResult, Error, any, unknown>;
|
|
26
|
+
showPathParamsWarning: boolean;
|
|
27
|
+
}) => {
|
|
28
|
+
const status = ((queryMutation.data?.status ?? 0) / 100).toFixed(0);
|
|
29
|
+
return (
|
|
30
|
+
<div className="min-w-0 p-8 bg-muted/70 overflow-y-auto">
|
|
31
|
+
{queryMutation.error ? (
|
|
32
|
+
<div className="flex flex-col gap-2">
|
|
33
|
+
{showPathParamsWarning && (
|
|
34
|
+
<Callout type="caution">
|
|
35
|
+
Some path parameters are missing values. Please fill them in to
|
|
36
|
+
ensure the request is sent correctly.
|
|
37
|
+
</Callout>
|
|
38
|
+
)}
|
|
39
|
+
<Card>
|
|
40
|
+
<CardHeader>
|
|
41
|
+
<CardTitle>Request failed</CardTitle>
|
|
42
|
+
</CardHeader>
|
|
43
|
+
<CardContent>
|
|
44
|
+
Error:{" "}
|
|
45
|
+
{queryMutation.error.message ||
|
|
46
|
+
String(queryMutation.error) ||
|
|
47
|
+
"Unexpected error"}
|
|
48
|
+
</CardContent>
|
|
49
|
+
</Card>
|
|
50
|
+
</div>
|
|
51
|
+
) : queryMutation.data ? (
|
|
52
|
+
<div className="flex flex-col gap-2">
|
|
53
|
+
<Tabs defaultValue="response">
|
|
54
|
+
<TabsList>
|
|
55
|
+
<TabsTrigger value="request">Request</TabsTrigger>
|
|
56
|
+
<TabsTrigger value="response">
|
|
57
|
+
Response
|
|
58
|
+
<span
|
|
59
|
+
className={cn(
|
|
60
|
+
"text-xs font-mono ml-1",
|
|
61
|
+
status === "2" && "text-green-500",
|
|
62
|
+
status === "3" && "text-blue-500",
|
|
63
|
+
status === "4" && "text-yellow-500",
|
|
64
|
+
status === "5" && "text-red-500",
|
|
65
|
+
)}
|
|
66
|
+
>
|
|
67
|
+
({queryMutation.data.status})
|
|
68
|
+
</span>
|
|
69
|
+
</TabsTrigger>
|
|
70
|
+
</TabsList>
|
|
71
|
+
<TabsContent value="request">
|
|
72
|
+
<RequestTab {...queryMutation.data.request} />
|
|
73
|
+
</TabsContent>
|
|
74
|
+
<TabsContent value="response">
|
|
75
|
+
<ResponseTab
|
|
76
|
+
status={queryMutation.data.status}
|
|
77
|
+
time={queryMutation.data.time}
|
|
78
|
+
size={queryMutation.data.size}
|
|
79
|
+
headers={queryMutation.data.headers}
|
|
80
|
+
body={queryMutation.data.body}
|
|
81
|
+
url={queryMutation.data.request.url}
|
|
82
|
+
/>
|
|
83
|
+
</TabsContent>
|
|
84
|
+
</Tabs>
|
|
85
|
+
</div>
|
|
86
|
+
) : (
|
|
87
|
+
<div className="grid place-items-center h-full">
|
|
88
|
+
<span className="text-[16px] font-semibold text-muted-foreground">
|
|
89
|
+
{queryMutation.isPending ? (
|
|
90
|
+
<Spinner />
|
|
91
|
+
) : (
|
|
92
|
+
"Send a request first to see the response here"
|
|
93
|
+
)}
|
|
94
|
+
</span>
|
|
95
|
+
</div>
|
|
96
|
+
)}
|
|
97
|
+
</div>
|
|
98
|
+
);
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export default ResultPanel;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { generateInterface } from "./convertToTypes.js";
|
|
3
|
+
|
|
4
|
+
describe("generateInterface", () => {
|
|
5
|
+
it("should handle primitive types", () => {
|
|
6
|
+
const input = {
|
|
7
|
+
string: "hello",
|
|
8
|
+
number: 42,
|
|
9
|
+
boolean: true,
|
|
10
|
+
null: null,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const expected = [
|
|
14
|
+
"{",
|
|
15
|
+
" string: string;",
|
|
16
|
+
" number: number;",
|
|
17
|
+
" boolean: boolean;",
|
|
18
|
+
" null: null;",
|
|
19
|
+
"}",
|
|
20
|
+
].join("\n");
|
|
21
|
+
|
|
22
|
+
expect(generateInterface(input)).toBe(expected);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("should handle nested objects", () => {
|
|
26
|
+
const input = {
|
|
27
|
+
user: {
|
|
28
|
+
name: "John",
|
|
29
|
+
age: 30,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const expected = [
|
|
34
|
+
"{",
|
|
35
|
+
" user: {",
|
|
36
|
+
" name: string;",
|
|
37
|
+
" age: number;",
|
|
38
|
+
"};",
|
|
39
|
+
"}",
|
|
40
|
+
].join("\n");
|
|
41
|
+
|
|
42
|
+
expect(generateInterface(input)).toBe(expected);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("should handle arrays", () => {
|
|
46
|
+
const input = {
|
|
47
|
+
numbers: [1, 2, 3],
|
|
48
|
+
empty: [],
|
|
49
|
+
objects: [{ id: 1 }],
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const expected = [
|
|
53
|
+
"{",
|
|
54
|
+
" numbers: number[];",
|
|
55
|
+
" empty: any[];",
|
|
56
|
+
" objects: {",
|
|
57
|
+
" id: number;",
|
|
58
|
+
"}[];",
|
|
59
|
+
"}",
|
|
60
|
+
].join("\n");
|
|
61
|
+
|
|
62
|
+
expect(generateInterface(input)).toBe(expected);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
type JsonValue = string | number | boolean | null | JsonObject | JsonArray;
|
|
2
|
+
type JsonObject = { [key: string]: JsonValue };
|
|
3
|
+
type JsonArray = JsonValue[];
|
|
4
|
+
|
|
5
|
+
function inferType(value: JsonValue): string {
|
|
6
|
+
if (value === null) return "null";
|
|
7
|
+
if (Array.isArray(value)) {
|
|
8
|
+
if (value.length === 0) return "any[]";
|
|
9
|
+
const firstValue = value[0];
|
|
10
|
+
if (firstValue === undefined) return "any[]";
|
|
11
|
+
const elementType = inferType(firstValue);
|
|
12
|
+
return `${elementType}[]`;
|
|
13
|
+
}
|
|
14
|
+
if (typeof value === "object") {
|
|
15
|
+
return generateInterface(value);
|
|
16
|
+
}
|
|
17
|
+
return typeof value;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function generateInterface(obj: JsonObject, indentation = ""): string {
|
|
21
|
+
const lines: string[] = ["{"];
|
|
22
|
+
|
|
23
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
24
|
+
const propertyType = inferType(value);
|
|
25
|
+
lines.push(` ${key}: ${propertyType};`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
lines.push("}");
|
|
29
|
+
return lines.join("\n");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function convertToTypes(json: JsonValue): { lines: string[] } {
|
|
33
|
+
const typeDefinition = inferType(json);
|
|
34
|
+
const lines = [`type GeneratedType = ${typeDefinition};`];
|
|
35
|
+
return { lines };
|
|
36
|
+
}
|
|
@@ -3,7 +3,7 @@ import { ListPlusIcon, RefreshCcwDotIcon } from "lucide-react";
|
|
|
3
3
|
import { useCallback, useState } from "react";
|
|
4
4
|
import { Badge } from "zudoku/ui/Badge.js";
|
|
5
5
|
import { Markdown, ProseClasses } from "../../../components/Markdown.js";
|
|
6
|
-
import { CIRCULAR_REF } from "../../../oas/
|
|
6
|
+
import { CIRCULAR_REF } from "../../../oas/graphql/circular.js";
|
|
7
7
|
import type { SchemaObject } from "../../../oas/parser/index.js";
|
|
8
8
|
import { Button } from "../../../ui/Button.js";
|
|
9
9
|
import { cn } from "../../../util/cn.js";
|
package/src/lib/ui/Command.tsx
CHANGED
|
@@ -61,7 +61,7 @@ const CommandInlineInput = React.forwardRef<
|
|
|
61
61
|
<CommandPrimitive.Input
|
|
62
62
|
ref={ref}
|
|
63
63
|
className={cn(
|
|
64
|
-
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none
|
|
64
|
+
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50",
|
|
65
65
|
"focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
66
66
|
className,
|
|
67
67
|
)}
|
package/src/lib/ui/Select.tsx
CHANGED
|
@@ -83,9 +83,9 @@ const SelectContent = React.forwardRef<
|
|
|
83
83
|
<SelectScrollUpButton />
|
|
84
84
|
<SelectPrimitive.Viewport
|
|
85
85
|
className={cn(
|
|
86
|
-
"p-1",
|
|
87
86
|
position === "popper" &&
|
|
88
87
|
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]",
|
|
88
|
+
"divide-y",
|
|
89
89
|
)}
|
|
90
90
|
>
|
|
91
91
|
{children}
|
|
@@ -61,7 +61,7 @@ export const MdxComponents = {
|
|
|
61
61
|
code: ({ className, children, ...props }) => {
|
|
62
62
|
// `inline` provided by the rehype plugin, as react-markdown removed support for that
|
|
63
63
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
64
|
-
const inline =
|
|
64
|
+
const { inline, title } = props as Record<string, unknown>;
|
|
65
65
|
|
|
66
66
|
if (inline === true || inline === "true") {
|
|
67
67
|
return <InlineCode className={className}>{children}</InlineCode>;
|
|
@@ -75,6 +75,7 @@ export const MdxComponents = {
|
|
|
75
75
|
className="rounded-xl p-4 border dark:!bg-foreground/10 dark:border-transparent"
|
|
76
76
|
showLanguageIndicator
|
|
77
77
|
code={String(children).trim()}
|
|
78
|
+
title={typeof title === "string" ? title : undefined}
|
|
78
79
|
/>
|
|
79
80
|
);
|
|
80
81
|
},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect } from "react";
|
|
1
|
+
import { useCallback, useEffect } from "react";
|
|
2
2
|
import { useLocation } from "react-router";
|
|
3
3
|
import { useViewportAnchor } from "../components/context/ViewportAnchorContext.js";
|
|
4
4
|
import { DATA_ANCHOR_ATTR } from "../components/navigation/SidebarItem.js";
|
|
@@ -22,32 +22,49 @@ const scrollIntoViewIfNeeded = (
|
|
|
22
22
|
element.scrollIntoView(options);
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
-
export const
|
|
26
|
-
const location = useLocation();
|
|
25
|
+
export const useScrollToHash = () => {
|
|
27
26
|
const { setActiveAnchor } = useViewportAnchor();
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
28
|
+
const scrollToHash = useCallback(
|
|
29
|
+
(hash: string) => {
|
|
30
|
+
const cleanHash = hash
|
|
31
|
+
.replace(/^#/, "")
|
|
32
|
+
// Operation list items might have subdivisions that the sidebar doesn't show.
|
|
33
|
+
// The subdivisions are separated by a slash so we need to remove everything before the slash to get the sidebar correct item.
|
|
34
|
+
.split("/")
|
|
35
|
+
.at(0)!;
|
|
36
|
+
const element = document.getElementById(decodeURIComponent(cleanHash));
|
|
37
|
+
const link = document.querySelector(
|
|
38
|
+
`[${DATA_ANCHOR_ATTR}="${cleanHash}"]`,
|
|
39
|
+
);
|
|
37
40
|
|
|
38
41
|
if (element) {
|
|
39
42
|
element.scrollIntoView();
|
|
40
43
|
scrollIntoViewIfNeeded(link);
|
|
41
|
-
requestIdleCallback(() => setActiveAnchor(
|
|
44
|
+
requestIdleCallback(() => setActiveAnchor(cleanHash));
|
|
42
45
|
return true;
|
|
43
46
|
}
|
|
44
47
|
|
|
48
|
+
// Scroll didn't happen
|
|
45
49
|
return false;
|
|
46
|
-
}
|
|
50
|
+
},
|
|
51
|
+
[setActiveAnchor],
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
return scrollToHash;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const useScrollToAnchor = () => {
|
|
58
|
+
const location = useLocation();
|
|
59
|
+
const { setActiveAnchor } = useViewportAnchor();
|
|
60
|
+
const scrollToHash = useScrollToHash();
|
|
61
|
+
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
if (!location.hash) return;
|
|
47
64
|
|
|
48
|
-
if (!
|
|
65
|
+
if (!scrollToHash(location.hash)) {
|
|
49
66
|
const observer = new MutationObserver((_, obs) => {
|
|
50
|
-
if (!
|
|
67
|
+
if (!scrollToHash(location.hash)) return;
|
|
51
68
|
obs.disconnect();
|
|
52
69
|
});
|
|
53
70
|
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from "react";
|
|
3
|
-
import { SyntaxHighlight } from "../../../components/SyntaxHighlight.js";
|
|
4
|
-
import { Card } from "../../../ui/Card.js";
|
|
5
|
-
import { SimpleSelect } from "../SimpleSelect.js";
|
|
6
|
-
const mimeTypeToLanguage = (mimeType) => {
|
|
7
|
-
const mimeTypeMapping = {
|
|
8
|
-
"application/json": "json",
|
|
9
|
-
"text/json": "json",
|
|
10
|
-
"text/html": "html",
|
|
11
|
-
"text/css": "css",
|
|
12
|
-
"text/javascript": "javascript",
|
|
13
|
-
"application/xml": "xml",
|
|
14
|
-
"application/xhtml+xml": "xhtml",
|
|
15
|
-
};
|
|
16
|
-
return Object.entries(mimeTypeMapping).find(([mime]) => mimeType.includes(mime))?.[1];
|
|
17
|
-
};
|
|
18
|
-
const detectLanguage = (headers) => {
|
|
19
|
-
const contentType = headers.get("Content-Type") || "";
|
|
20
|
-
return mimeTypeToLanguage(contentType);
|
|
21
|
-
};
|
|
22
|
-
const tryParseJson = (body) => {
|
|
23
|
-
try {
|
|
24
|
-
return JSON.stringify(JSON.parse(body), null, 2);
|
|
25
|
-
}
|
|
26
|
-
catch {
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
export const ResponseTab = ({ body = "", headers, }) => {
|
|
31
|
-
const detectedLanguage = detectLanguage(headers);
|
|
32
|
-
const jsonContent = tryParseJson(body);
|
|
33
|
-
const beautifiedBody = jsonContent || body;
|
|
34
|
-
const [view, setView] = useState(jsonContent ? "formatted" : "raw");
|
|
35
|
-
return (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Card, { className: "shadow-none", children: _jsx(SyntaxHighlight, { language: view === "raw" ? (jsonContent ? "plain" : detectedLanguage) : "json", noBackground: true,
|
|
36
|
-
// playground dialog has h-5/6 ≈ 83.333vh
|
|
37
|
-
className: "overflow-x-auto p-4 text-xs max-h-[calc(83.333vh-180px)]", code: view === "raw" ? body : beautifiedBody }) }), jsonContent && (_jsx("div", { className: "flex justify-end", children: _jsx(SimpleSelect, { value: view, onChange: (e) => setView(e.target.value), options: [
|
|
38
|
-
{ value: "formatted", label: "Formatted" },
|
|
39
|
-
{ value: "raw", label: "Raw" },
|
|
40
|
-
] }) }))] }));
|
|
41
|
-
};
|
|
42
|
-
//# sourceMappingURL=ResponseTab.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ResponseTab.js","sourceRoot":"","sources":["../../../../../src/lib/plugins/openapi/playground/ResponseTab.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,wCAAwC,CAAC;AACzE,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,kBAAkB,GAAG,CAAC,QAAgB,EAAE,EAAE;IAC9C,MAAM,eAAe,GAAG;QACtB,kBAAkB,EAAE,MAAM;QAC1B,WAAW,EAAE,MAAM;QACnB,WAAW,EAAE,MAAM;QACnB,UAAU,EAAE,KAAK;QACjB,iBAAiB,EAAE,YAAY;QAC/B,iBAAiB,EAAE,KAAK;QACxB,uBAAuB,EAAE,OAAO;KACjC,CAAC;IAEF,OAAO,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CACrD,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CACxB,EAAE,CAAC,CAAC,CAAC,CAAC;AACT,CAAC,CAAC;AAEF,MAAM,cAAc,GAAG,CAAC,OAAgB,EAAE,EAAE;IAC1C,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;IACtD,OAAO,kBAAkB,CAAC,WAAW,CAAC,CAAC;AACzC,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,IAAY,EAAE,EAAE;IACpC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,EAC1B,IAAI,GAAG,EAAE,EACT,OAAO,GAIR,EAAE,EAAE;IACH,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IACjD,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,cAAc,GAAG,WAAW,IAAI,IAAI,CAAC;IAC3C,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAC9B,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAClC,CAAC;IAEF,OAAO,CACL,eAAK,SAAS,EAAC,qBAAqB,aAClC,KAAC,IAAI,IAAC,SAAS,EAAC,aAAa,YAC3B,KAAC,eAAe,IACd,QAAQ,EACN,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,MAAM,EAEtE,YAAY;oBACZ,yCAAyC;oBACzC,SAAS,EAAC,0DAA0D,EACpE,IAAI,EAAE,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,cAAc,GAC5C,GACG,EACN,WAAW,IAAI,CACd,cAAK,SAAS,EAAC,kBAAkB,YAC/B,KAAC,YAAY,IACX,KAAK,EAAE,IAAI,EACX,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAA4B,CAAC,EAC/D,OAAO,EAAE;wBACP,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE;wBAC1C,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE;qBAC/B,GACD,GACE,CACP,IACG,CACP,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import e from "react";
|
|
2
|
-
import { j as r } from "./jsx-runtime-Bdg6XQ1m.js";
|
|
3
|
-
import { u as l, L as m } from "./chunk-SYFQ2XB5-BF5IDYrB.js";
|
|
4
|
-
const c = {}, u = e.createContext(c);
|
|
5
|
-
function f(t) {
|
|
6
|
-
const n = e.useContext(u);
|
|
7
|
-
return e.useMemo(
|
|
8
|
-
function() {
|
|
9
|
-
return typeof t == "function" ? t(n) : { ...n, ...t };
|
|
10
|
-
},
|
|
11
|
-
[n, t]
|
|
12
|
-
);
|
|
13
|
-
}
|
|
14
|
-
function h(t) {
|
|
15
|
-
let n;
|
|
16
|
-
return t.disableParentContext ? n = typeof t.components == "function" ? t.components(c) : t.components || c : n = f(t.components), e.createElement(
|
|
17
|
-
u.Provider,
|
|
18
|
-
{ value: n },
|
|
19
|
-
t.children
|
|
20
|
-
);
|
|
21
|
-
}
|
|
22
|
-
const y = (t) => {
|
|
23
|
-
const n = l(), o = typeof t.to == "string" ? t.to : t.to.hash, i = (a) => {
|
|
24
|
-
var s;
|
|
25
|
-
!(o != null && o.startsWith("#")) || o !== n.hash || (a.preventDefault(), (s = document.getElementById(o.slice(1))) == null || s.scrollIntoView());
|
|
26
|
-
};
|
|
27
|
-
return /* @__PURE__ */ r.jsx(m, { onClick: i, ...t });
|
|
28
|
-
};
|
|
29
|
-
export {
|
|
30
|
-
y as A,
|
|
31
|
-
h as M,
|
|
32
|
-
f as u
|
|
33
|
-
};
|
|
34
|
-
//# sourceMappingURL=AnchorLink-bObQitZv.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AnchorLink-bObQitZv.js","sources":["../../../node_modules/.pnpm/@mdx-js+react@3.1.0_@types+react@19.0.7_react@19.0.0/node_modules/@mdx-js/react/lib/index.js","../src/lib/components/AnchorLink.tsx"],"sourcesContent":["/**\n * @import {MDXComponents} from 'mdx/types.js'\n * @import {Component, ReactElement, ReactNode} from 'react'\n */\n\n/**\n * @callback MergeComponents\n * Custom merge function.\n * @param {Readonly<MDXComponents>} currentComponents\n * Current components from the context.\n * @returns {MDXComponents}\n * Additional components.\n *\n * @typedef Props\n * Configuration for `MDXProvider`.\n * @property {ReactNode | null | undefined} [children]\n * Children (optional).\n * @property {Readonly<MDXComponents> | MergeComponents | null | undefined} [components]\n * Additional components to use or a function that creates them (optional).\n * @property {boolean | null | undefined} [disableParentContext=false]\n * Turn off outer component context (default: `false`).\n */\n\nimport React from 'react'\n\n/** @type {Readonly<MDXComponents>} */\nconst emptyComponents = {}\n\nconst MDXContext = React.createContext(emptyComponents)\n\n/**\n * Get current components from the MDX Context.\n *\n * @param {Readonly<MDXComponents> | MergeComponents | null | undefined} [components]\n * Additional components to use or a function that creates them (optional).\n * @returns {MDXComponents}\n * Current components.\n */\nexport function useMDXComponents(components) {\n const contextComponents = React.useContext(MDXContext)\n\n // Memoize to avoid unnecessary top-level context changes\n return React.useMemo(\n function () {\n // Custom merge via a function prop\n if (typeof components === 'function') {\n return components(contextComponents)\n }\n\n return {...contextComponents, ...components}\n },\n [contextComponents, components]\n )\n}\n\n/**\n * Provider for MDX context.\n *\n * @param {Readonly<Props>} properties\n * Properties.\n * @returns {ReactElement}\n * Element.\n * @satisfies {Component}\n */\nexport function MDXProvider(properties) {\n /** @type {Readonly<MDXComponents>} */\n let allComponents\n\n if (properties.disableParentContext) {\n allComponents =\n typeof properties.components === 'function'\n ? properties.components(emptyComponents)\n : properties.components || emptyComponents\n } else {\n allComponents = useMDXComponents(properties.components)\n }\n\n return React.createElement(\n MDXContext.Provider,\n {value: allComponents},\n properties.children\n )\n}\n","import React from \"react\";\nimport { Link, type LinkProps, useLocation } from \"react-router\";\n\n/**\n * Link that scrolls to anchor even if the hash is already set in the URL.\n */\nexport const AnchorLink = (props: LinkProps) => {\n const location = useLocation();\n const hash = typeof props.to === \"string\" ? props.to : props.to.hash;\n\n const handleClick = (event: React.MouseEvent<HTMLAnchorElement>) => {\n if (!hash?.startsWith(\"#\") || hash !== location.hash) return;\n\n event.preventDefault();\n document.getElementById(hash.slice(1))?.scrollIntoView();\n };\n\n return <Link onClick={handleClick} {...props} />;\n};\n"],"names":["emptyComponents","MDXContext","React","useMDXComponents","components","contextComponents","MDXProvider","properties","allComponents","AnchorLink","props","location","useLocation","hash","handleClick","event","_a","jsx","Link"],"mappings":";;;AA0BA,MAAMA,IAAkB,CAAA,GAElBC,IAAaC,EAAM,cAAcF,CAAe;AAU/C,SAASG,EAAiBC,GAAY;AAC3C,QAAMC,IAAoBH,EAAM,WAAWD,CAAU;AAGrD,SAAOC,EAAM;AAAA,IACX,WAAY;AAEV,aAAI,OAAOE,KAAe,aACjBA,EAAWC,CAAiB,IAG9B,EAAC,GAAGA,GAAmB,GAAGD,EAAU;AAAA,IAC5C;AAAA,IACD,CAACC,GAAmBD,CAAU;AAAA,EAClC;AACA;AAWO,SAASE,EAAYC,GAAY;AAEtC,MAAIC;AAEJ,SAAID,EAAW,uBACbC,IACE,OAAOD,EAAW,cAAe,aAC7BA,EAAW,WAAWP,CAAe,IACrCO,EAAW,cAAcP,IAE/BQ,IAAgBL,EAAiBI,EAAW,UAAU,GAGjDL,EAAM;AAAA,IACXD,EAAW;AAAA,IACX,EAAC,OAAOO,EAAa;AAAA,IACrBD,EAAW;AAAA,EACf;AACA;AC5Ea,MAAAE,IAAa,CAACC,MAAqB;AAC9C,QAAMC,IAAWC,EAAY,GACvBC,IAAO,OAAOH,EAAM,MAAO,WAAWA,EAAM,KAAKA,EAAM,GAAG,MAE1DI,IAAc,CAACC,MAA+C;;AAClE,IAAI,EAACF,KAAA,QAAAA,EAAM,WAAW,SAAQA,MAASF,EAAS,SAEhDI,EAAM,eAAe,IACrBC,IAAA,SAAS,eAAeH,EAAK,MAAM,CAAC,CAAC,MAArC,QAAAG,EAAwC;AAAA,EAC1C;AAEA,SAAQC,gBAAAA,EAAAA,IAAAC,GAAA,EAAK,SAASJ,GAAc,GAAGJ,GAAO;AAChD;","x_google_ignoreList":[0]}
|