fumadocs-openapi 10.3.10 → 10.3.12
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/css/generated/shared.css +29 -5
- package/dist/playground/client.js +20 -15
- package/dist/playground/components/inputs.js +88 -64
- package/dist/playground/index.d.ts +1 -1
- package/dist/playground/index.js +1 -1
- package/dist/playground/schema.d.ts +1 -0
- package/dist/playground/schema.js +57 -35
- package/dist/ui/components/select.js +1 -1
- package/dist/ui/full.js +2 -2
- package/dist/ui/operation/request-tabs.js +1 -1
- package/dist/ui/operation/response-tabs.js +1 -1
- package/dist/ui/schema/client.js +40 -17
- package/dist/ui/schema/index.d.ts +6 -5
- package/dist/ui/schema/index.js +1 -1
- package/dist/utils/schema-to-string.d.ts +2 -0
- package/dist/utils/schema-to-string.js +11 -2
- package/dist/utils/schema.d.ts +3 -1
- package/package.json +4 -4
- package/dist/playground/get-default-values.js +0 -23
package/css/generated/shared.css
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
@source inline("!isDefined");
|
|
2
|
+
@source inline("!last");
|
|
3
|
+
@source inline("*:data-[collapsible=true]:order-last");
|
|
2
4
|
@source inline("*:min-w-0");
|
|
3
5
|
@source inline("--fd-docs-row-1");
|
|
4
6
|
@source inline("--initial-height");
|
|
@@ -25,7 +27,6 @@
|
|
|
25
27
|
@source inline("@scalar/api-client-react");
|
|
26
28
|
@source inline("@see");
|
|
27
29
|
@source inline("@typescript-eslint/no-explicit-any");
|
|
28
|
-
@source inline("[&_svg]:size-3.5");
|
|
29
30
|
@source inline("a");
|
|
30
31
|
@source inline("absolute");
|
|
31
32
|
@source inline("access");
|
|
@@ -99,6 +100,7 @@
|
|
|
99
100
|
@source inline("border-fd-primary/20");
|
|
100
101
|
@source inline("border-t");
|
|
101
102
|
@source inline("border-x");
|
|
103
|
+
@source inline("border-y");
|
|
102
104
|
@source inline("both");
|
|
103
105
|
@source inline("but");
|
|
104
106
|
@source inline("button");
|
|
@@ -123,6 +125,7 @@
|
|
|
123
125
|
@source inline("client");
|
|
124
126
|
@source inline("client-side");
|
|
125
127
|
@source inline("clientCredentials");
|
|
128
|
+
@source inline("clientHeight");
|
|
126
129
|
@source inline("clientId");
|
|
127
130
|
@source inline("clientSecret");
|
|
128
131
|
@source inline("client_credentials");
|
|
@@ -158,6 +161,7 @@
|
|
|
158
161
|
@source inline("ctx");
|
|
159
162
|
@source inline("current");
|
|
160
163
|
@source inline("currentId");
|
|
164
|
+
@source inline("currentRef");
|
|
161
165
|
@source inline("currentValue");
|
|
162
166
|
@source inline("customisation");
|
|
163
167
|
@source inline("cva");
|
|
@@ -177,6 +181,8 @@
|
|
|
177
181
|
@source inline("data-[state=open]:animate-fd-fade-in");
|
|
178
182
|
@source inline("data-[state=open]:rounded-b-none");
|
|
179
183
|
@source inline("data-[state=open]:text-fd-accent-foreground");
|
|
184
|
+
@source inline("data-collapsible");
|
|
185
|
+
@source inline("data-placeholder:text-fd-muted-foreground");
|
|
180
186
|
@source inline("dataEngine");
|
|
181
187
|
@source inline("declare");
|
|
182
188
|
@source inline("default");
|
|
@@ -187,6 +193,7 @@
|
|
|
187
193
|
@source inline("defaultSamples");
|
|
188
194
|
@source inline("defaultValue");
|
|
189
195
|
@source inline("defaultValues");
|
|
196
|
+
@source inline("deferredValue");
|
|
190
197
|
@source inline("definitions");
|
|
191
198
|
@source inline("deprecated");
|
|
192
199
|
@source inline("depth");
|
|
@@ -252,6 +259,7 @@
|
|
|
252
259
|
@source inline("file");
|
|
253
260
|
@source inline("filePath");
|
|
254
261
|
@source inline("files");
|
|
262
|
+
@source inline("filtered");
|
|
255
263
|
@source inline("find");
|
|
256
264
|
@source inline("fine");
|
|
257
265
|
@source inline("first");
|
|
@@ -268,6 +276,8 @@
|
|
|
268
276
|
@source inline("focus-visible:outline-none");
|
|
269
277
|
@source inline("focus-visible:ring-1");
|
|
270
278
|
@source inline("focus-visible:ring-fd-ring");
|
|
279
|
+
@source inline("focus-within:ring-2");
|
|
280
|
+
@source inline("focus-within:ring-fd-ring");
|
|
271
281
|
@source inline("focus:bg-fd-accent");
|
|
272
282
|
@source inline("focus:outline-none");
|
|
273
283
|
@source inline("focus:ring");
|
|
@@ -306,12 +316,12 @@
|
|
|
306
316
|
@source inline("gap-x-6");
|
|
307
317
|
@source inline("gap-y-4");
|
|
308
318
|
@source inline("generate");
|
|
319
|
+
@source inline("generateDefault");
|
|
309
320
|
@source inline("generated");
|
|
310
321
|
@source inline("generated/defined");
|
|
311
322
|
@source inline("generator");
|
|
312
323
|
@source inline("generators");
|
|
313
324
|
@source inline("getAPIPageProps");
|
|
314
|
-
@source inline("getDefaultValue");
|
|
315
325
|
@source inline("getSchema");
|
|
316
326
|
@source inline("getStatusInfo");
|
|
317
327
|
@source inline("getTypescriptSchema");
|
|
@@ -339,6 +349,7 @@
|
|
|
339
349
|
@source inline("headers");
|
|
340
350
|
@source inline("headingLevel");
|
|
341
351
|
@source inline("hidden");
|
|
352
|
+
@source inline("hiddenProperties");
|
|
342
353
|
@source inline("hook");
|
|
343
354
|
@source inline("hover:bg-fd-accent");
|
|
344
355
|
@source inline("hover:text-fd-accent-foreground");
|
|
@@ -381,6 +392,7 @@
|
|
|
381
392
|
@source inline("isDefined");
|
|
382
393
|
@source inline("isDuplicated");
|
|
383
394
|
@source inline("isDynamic");
|
|
395
|
+
@source inline("isLazy");
|
|
384
396
|
@source inline("isLoading");
|
|
385
397
|
@source inline("isMediaTypeSupported");
|
|
386
398
|
@source inline("isNumber");
|
|
@@ -426,7 +438,6 @@
|
|
|
426
438
|
@source inline("lucide-react");
|
|
427
439
|
@source inline("map");
|
|
428
440
|
@source inline("mapInputs");
|
|
429
|
-
@source inline("match");
|
|
430
441
|
@source inline("max");
|
|
431
442
|
@source inline("max-age");
|
|
432
443
|
@source inline("max-h-[460px]");
|
|
@@ -453,6 +464,7 @@
|
|
|
453
464
|
@source inline("module");
|
|
454
465
|
@source inline("moon");
|
|
455
466
|
@source inline("mounted");
|
|
467
|
+
@source inline("ms-2");
|
|
456
468
|
@source inline("ms-auto");
|
|
457
469
|
@source inline("mt-10");
|
|
458
470
|
@source inline("mt-2");
|
|
@@ -467,6 +479,7 @@
|
|
|
467
479
|
@source inline("my-4");
|
|
468
480
|
@source inline("name");
|
|
469
481
|
@source inline("name!");
|
|
482
|
+
@source inline("namespace");
|
|
470
483
|
@source inline("necessary");
|
|
471
484
|
@source inline("need");
|
|
472
485
|
@source inline("nested");
|
|
@@ -492,7 +505,6 @@
|
|
|
492
505
|
@source inline("onChange");
|
|
493
506
|
@source inline("onClick");
|
|
494
507
|
@source inline("onCopy");
|
|
495
|
-
@source inline("onDelete");
|
|
496
508
|
@source inline("onKeyDown");
|
|
497
509
|
@source inline("onOpenChange");
|
|
498
510
|
@source inline("onSubmit");
|
|
@@ -512,6 +524,7 @@
|
|
|
512
524
|
@source inline("options");
|
|
513
525
|
@source inline("or");
|
|
514
526
|
@source inline("orange");
|
|
527
|
+
@source inline("order-last");
|
|
515
528
|
@source inline("origin");
|
|
516
529
|
@source inline("original");
|
|
517
530
|
@source inline("other");
|
|
@@ -567,12 +580,14 @@
|
|
|
567
580
|
@source inline("placeholder");
|
|
568
581
|
@source inline("placeholder:text-fd-muted-foreground");
|
|
569
582
|
@source inline("playground");
|
|
583
|
+
@source inline("playground/index.tsx");
|
|
570
584
|
@source inline("playgroundEnabled");
|
|
571
585
|
@source inline("playgrounds");
|
|
572
586
|
@source inline("plugins");
|
|
573
587
|
@source inline("position");
|
|
574
588
|
@source inline("pre");
|
|
575
589
|
@source inline("prefix");
|
|
590
|
+
@source inline("preprocessed");
|
|
576
591
|
@source inline("prev");
|
|
577
592
|
@source inline("prevent");
|
|
578
593
|
@source inline("primary");
|
|
@@ -586,6 +601,7 @@
|
|
|
586
601
|
@source inline("props");
|
|
587
602
|
@source inline("prose-no-margin");
|
|
588
603
|
@source inline("proxyUrl");
|
|
604
|
+
@source inline("ps-2");
|
|
589
605
|
@source inline("ps-4.5");
|
|
590
606
|
@source inline("ps-6");
|
|
591
607
|
@source inline("pt-1");
|
|
@@ -603,6 +619,7 @@
|
|
|
603
619
|
@source inline("py-2");
|
|
604
620
|
@source inline("py-4");
|
|
605
621
|
@source inline("query");
|
|
622
|
+
@source inline("quiet");
|
|
606
623
|
@source inline("race");
|
|
607
624
|
@source inline("range");
|
|
608
625
|
@source inline("raw");
|
|
@@ -612,6 +629,7 @@
|
|
|
612
629
|
@source inline("react/jsx-runtime");
|
|
613
630
|
@source inline("read");
|
|
614
631
|
@source inline("readOnly");
|
|
632
|
+
@source inline("recover");
|
|
615
633
|
@source inline("red");
|
|
616
634
|
@source inline("redirect_uri");
|
|
617
635
|
@source inline("ref");
|
|
@@ -653,6 +671,7 @@
|
|
|
653
671
|
@source inline("resType");
|
|
654
672
|
@source inline("reset");
|
|
655
673
|
@source inline("resize-none");
|
|
674
|
+
@source inline("resolution");
|
|
656
675
|
@source inline("resolveMediaAdapter");
|
|
657
676
|
@source inline("resolveRequestData");
|
|
658
677
|
@source inline("resolvedTheme");
|
|
@@ -679,6 +698,7 @@
|
|
|
679
698
|
@source inline("samples");
|
|
680
699
|
@source inline("satisfies");
|
|
681
700
|
@source inline("schema");
|
|
701
|
+
@source inline("schemaPropKeys");
|
|
682
702
|
@source inline("schemaToString");
|
|
683
703
|
@source inline("schemaUI");
|
|
684
704
|
@source inline("schemas");
|
|
@@ -724,6 +744,7 @@
|
|
|
724
744
|
@source inline("setNextName");
|
|
725
745
|
@source inline("setOpen");
|
|
726
746
|
@source inline("setPath");
|
|
747
|
+
@source inline("setSearch");
|
|
727
748
|
@source inline("setSecurityId");
|
|
728
749
|
@source inline("setServer");
|
|
729
750
|
@source inline("setServerVariables");
|
|
@@ -790,6 +811,7 @@
|
|
|
790
811
|
@source inline("such");
|
|
791
812
|
@source inline("summary");
|
|
792
813
|
@source inline("supported");
|
|
814
|
+
@source inline("swallow");
|
|
793
815
|
@source inline("switch");
|
|
794
816
|
@source inline("tab");
|
|
795
817
|
@source inline("tabs");
|
|
@@ -882,11 +904,12 @@
|
|
|
882
904
|
@source inline("useFieldValue");
|
|
883
905
|
@source inline("useForm");
|
|
884
906
|
@source inline("useMemo");
|
|
907
|
+
@source inline("useNamespace");
|
|
885
908
|
@source inline("useObject");
|
|
886
909
|
@source inline("useQuery");
|
|
887
910
|
@source inline("useRef");
|
|
888
|
-
@source inline("useResolvedSchema");
|
|
889
911
|
@source inline("useSchemaScope");
|
|
912
|
+
@source inline("useSchemaUtils");
|
|
890
913
|
@source inline("useServerContext");
|
|
891
914
|
@source inline("useServerSelectContext");
|
|
892
915
|
@source inline("useState");
|
|
@@ -933,6 +956,7 @@
|
|
|
933
956
|
@source inline("writeOnly");
|
|
934
957
|
@source inline("x-codeSamples");
|
|
935
958
|
@source inline("x-exclusiveCodeSample");
|
|
959
|
+
@source inline("x-playground-lazy");
|
|
936
960
|
@source inline("x-selectedCodeSample");
|
|
937
961
|
@source inline("yellow");
|
|
938
962
|
@source inline("you");
|
|
@@ -8,7 +8,7 @@ import { cn } from "../utils/cn.js";
|
|
|
8
8
|
import { MethodLabel } from "../ui/components/method-label.js";
|
|
9
9
|
import { useQuery } from "../utils/use-query.js";
|
|
10
10
|
import { encodeRequestData } from "../requests/media/encode.js";
|
|
11
|
-
import { SchemaProvider,
|
|
11
|
+
import { SchemaProvider, useSchemaUtils } from "./schema.js";
|
|
12
12
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../ui/components/select.js";
|
|
13
13
|
import { labelVariants } from "../ui/components/input.js";
|
|
14
14
|
import ServerSelect from "./components/server-select.js";
|
|
@@ -16,7 +16,7 @@ import { useExampleRequests } from "../ui/operation/usage-tabs/client.js";
|
|
|
16
16
|
import { FieldInput, FieldSet, JsonInput, ObjectInput } from "./components/inputs.js";
|
|
17
17
|
import { Fragment, lazy, useEffect, useMemo, useRef, useState } from "react";
|
|
18
18
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
19
|
-
import { ChevronDown, LoaderCircle
|
|
19
|
+
import { ChevronDown, LoaderCircle } from "lucide-react";
|
|
20
20
|
import { DynamicCodeBlock } from "fumadocs-ui/components/dynamic-codeblock.core";
|
|
21
21
|
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "fumadocs-ui/components/ui/collapsible";
|
|
22
22
|
import { buttonVariants } from "fumadocs-ui/components/ui/button";
|
|
@@ -121,6 +121,10 @@ function PlaygroundClient({ route, method = "GET", securities, parameters = [],
|
|
|
121
121
|
})
|
|
122
122
|
]
|
|
123
123
|
}),
|
|
124
|
+
testQuery.data ? /* @__PURE__ */ jsx(ResultDisplay, {
|
|
125
|
+
data: testQuery.data,
|
|
126
|
+
reset: testQuery.reset
|
|
127
|
+
}) : null,
|
|
124
128
|
securities.length > 0 && /* @__PURE__ */ jsx(SecurityTabs, {
|
|
125
129
|
securities,
|
|
126
130
|
securityId,
|
|
@@ -130,11 +134,7 @@ function PlaygroundClient({ route, method = "GET", securities, parameters = [],
|
|
|
130
134
|
/* @__PURE__ */ jsx(FormBody, {
|
|
131
135
|
body,
|
|
132
136
|
parameters
|
|
133
|
-
})
|
|
134
|
-
testQuery.data ? /* @__PURE__ */ jsx(ResultDisplay, {
|
|
135
|
-
data: testQuery.data,
|
|
136
|
-
reset: testQuery.reset
|
|
137
|
-
}) : null
|
|
137
|
+
})
|
|
138
138
|
]
|
|
139
139
|
})
|
|
140
140
|
})
|
|
@@ -206,7 +206,8 @@ function FormBody({ parameters = [], body }) {
|
|
|
206
206
|
return /* @__PURE__ */ jsx(FieldSet, {
|
|
207
207
|
name: field.name,
|
|
208
208
|
fieldName,
|
|
209
|
-
field: schema
|
|
209
|
+
field: schema,
|
|
210
|
+
isRequired: field.required
|
|
210
211
|
}, stringifyFieldKey(fieldName));
|
|
211
212
|
})
|
|
212
213
|
}, type);
|
|
@@ -217,11 +218,12 @@ function FormBody({ parameters = [], body }) {
|
|
|
217
218
|
})] });
|
|
218
219
|
}
|
|
219
220
|
function BodyInput({ field: _field }) {
|
|
220
|
-
const field =
|
|
221
|
+
const field = useSchemaUtils().resolve(_field);
|
|
221
222
|
const [isJson, setIsJson] = useState(false);
|
|
222
223
|
if (field.format === "binary") return /* @__PURE__ */ jsx(FieldSet, {
|
|
223
224
|
field,
|
|
224
|
-
fieldName: ["body"]
|
|
225
|
+
fieldName: ["body"],
|
|
226
|
+
isRequired: true
|
|
225
227
|
});
|
|
226
228
|
if (isJson) return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("button", {
|
|
227
229
|
className: cn(buttonVariants({
|
|
@@ -237,6 +239,7 @@ function BodyInput({ field: _field }) {
|
|
|
237
239
|
field,
|
|
238
240
|
fieldName: ["body"],
|
|
239
241
|
collapsible: false,
|
|
242
|
+
isRequired: true,
|
|
240
243
|
name: /* @__PURE__ */ jsx("button", {
|
|
241
244
|
type: "button",
|
|
242
245
|
className: cn(buttonVariants({
|
|
@@ -405,19 +408,21 @@ function DefaultResultDisplay({ data, reset }) {
|
|
|
405
408
|
const statusInfo = useMemo(() => getStatusInfo(data.status), [data.status]);
|
|
406
409
|
const { shikiOptions } = useApiContext();
|
|
407
410
|
return /* @__PURE__ */ jsxs("div", {
|
|
408
|
-
className: "flex flex-col gap-3
|
|
411
|
+
className: "flex flex-col gap-3 mt-2 px-3 py-2 border-y bg-fd-secondary text-fd-secondary-foreground",
|
|
409
412
|
children: [
|
|
410
413
|
/* @__PURE__ */ jsxs("div", {
|
|
411
414
|
className: "flex justify-between items-center",
|
|
412
415
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
413
|
-
className: "inline-flex items-center gap-1.5 text-sm font-medium
|
|
416
|
+
className: "inline-flex items-center gap-1.5 text-sm font-medium",
|
|
414
417
|
children: [/* @__PURE__ */ jsx(statusInfo.icon, { className: cn("size-4", statusInfo.color) }), statusInfo.description]
|
|
415
418
|
}), /* @__PURE__ */ jsx("button", {
|
|
416
419
|
type: "button",
|
|
417
|
-
className: cn(buttonVariants({
|
|
420
|
+
className: cn(buttonVariants({
|
|
421
|
+
size: "sm",
|
|
422
|
+
variant: "outline"
|
|
423
|
+
})),
|
|
418
424
|
onClick: () => reset(),
|
|
419
|
-
|
|
420
|
-
children: /* @__PURE__ */ jsx(X, {})
|
|
425
|
+
children: "Close"
|
|
421
426
|
})]
|
|
422
427
|
}),
|
|
423
428
|
/* @__PURE__ */ jsx("p", {
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { cn } from "../../utils/cn.js";
|
|
4
|
-
import {
|
|
5
|
-
import { anyFields, useFieldInfo,
|
|
4
|
+
import { FormatFlags } from "../../utils/schema-to-string.js";
|
|
5
|
+
import { anyFields, useFieldInfo, useSchemaScope, useSchemaUtils } from "../schema.js";
|
|
6
6
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../ui/components/select.js";
|
|
7
7
|
import { Input, labelVariants } from "../../ui/components/input.js";
|
|
8
|
-
import { FormatFlags, schemaToString } from "../../utils/schema-to-string.js";
|
|
9
8
|
import { useState } from "react";
|
|
10
9
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
11
10
|
import { ChevronRight, Plus, Trash2, X } from "lucide-react";
|
|
@@ -24,65 +23,84 @@ function FieldLabelType(props) {
|
|
|
24
23
|
});
|
|
25
24
|
}
|
|
26
25
|
function ObjectInput({ field: _field, fieldName, ...props }) {
|
|
27
|
-
const
|
|
26
|
+
const { resolve, generateDefault } = useSchemaUtils();
|
|
27
|
+
const field = resolve(_field);
|
|
28
|
+
const schemaPropKeys = field.properties ? Object.keys(field.properties) : [];
|
|
29
|
+
const { patternProperties = {}, additionalProperties, "x-playground-lazy": isLazy = schemaPropKeys.length > 100 } = field;
|
|
30
|
+
const isDynamic = Object.keys(patternProperties).length > 0 || additionalProperties;
|
|
28
31
|
const [nextName, setNextName] = useState("");
|
|
29
|
-
const { properties, onAppend, onDelete } = useObject(fieldName, {
|
|
30
|
-
|
|
32
|
+
const { properties, onAppend, onDelete, _objectKeys } = useObject(fieldName, {
|
|
33
|
+
lazy: isLazy,
|
|
34
|
+
defaultValue: () => generateDefault(field),
|
|
31
35
|
properties: field.properties ?? {},
|
|
32
|
-
fallback:
|
|
33
|
-
patternProperties
|
|
36
|
+
fallback: additionalProperties,
|
|
37
|
+
patternProperties
|
|
34
38
|
});
|
|
35
|
-
const
|
|
39
|
+
const hiddenProperties = isLazy ? schemaPropKeys.filter((key) => !_objectKeys.includes(key)) : [];
|
|
36
40
|
return /* @__PURE__ */ jsxs("div", {
|
|
37
41
|
...props,
|
|
38
|
-
className: cn("grid grid-cols-1 gap-4 @md:grid-cols-2", props.className),
|
|
39
|
-
children: [
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
42
|
+
className: cn("grid grid-cols-1 gap-4 @md:grid-cols-2 *:data-[collapsible=true]:order-last", props.className),
|
|
43
|
+
children: [
|
|
44
|
+
isLazy && hiddenProperties.length > 0 && /* @__PURE__ */ jsxs(Select, {
|
|
45
|
+
value: "",
|
|
46
|
+
onValueChange: onAppend,
|
|
47
|
+
children: [/* @__PURE__ */ jsx(SelectTrigger, {
|
|
48
|
+
className: "col-span-full",
|
|
49
|
+
children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Show Property" })
|
|
50
|
+
}), /* @__PURE__ */ jsx(SelectContent, { children: hiddenProperties.map((key) => /* @__PURE__ */ jsx(SelectItem, {
|
|
51
|
+
value: key,
|
|
52
|
+
children: key
|
|
53
|
+
}, key)) })]
|
|
54
|
+
}),
|
|
55
|
+
properties.map((child) => {
|
|
56
|
+
let toolbar = null;
|
|
57
|
+
if (child.kind === "pattern" || child.kind === "fallback") toolbar = /* @__PURE__ */ jsx("button", {
|
|
58
|
+
type: "button",
|
|
59
|
+
"aria-label": "Remove Item",
|
|
60
|
+
className: cn(buttonVariants({
|
|
61
|
+
color: "outline",
|
|
62
|
+
size: "icon-xs"
|
|
63
|
+
})),
|
|
64
|
+
onClick: () => {
|
|
65
|
+
onDelete(child.key);
|
|
66
|
+
},
|
|
67
|
+
children: /* @__PURE__ */ jsx(Trash2, {})
|
|
68
|
+
});
|
|
69
|
+
return /* @__PURE__ */ jsx(FieldSet, {
|
|
70
|
+
name: child.key,
|
|
71
|
+
field: child.info,
|
|
72
|
+
fieldName: child.field,
|
|
73
|
+
isRequired: field.required?.includes(child.key),
|
|
74
|
+
toolbar
|
|
75
|
+
}, child.key);
|
|
76
|
+
}),
|
|
77
|
+
isDynamic && /* @__PURE__ */ jsxs("div", {
|
|
78
|
+
className: "flex gap-2 order-last col-span-full",
|
|
79
|
+
children: [/* @__PURE__ */ jsx(Input, {
|
|
80
|
+
value: nextName,
|
|
81
|
+
placeholder: "Enter Property Name",
|
|
82
|
+
onChange: (e) => setNextName(e.target.value),
|
|
83
|
+
onKeyDown: (e) => {
|
|
84
|
+
if (e.key === "Enter") {
|
|
85
|
+
setNextName("");
|
|
86
|
+
onAppend(nextName);
|
|
87
|
+
e.preventDefault();
|
|
88
|
+
}
|
|
71
89
|
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
})
|
|
85
|
-
|
|
90
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
91
|
+
type: "button",
|
|
92
|
+
className: cn(buttonVariants({
|
|
93
|
+
color: "secondary",
|
|
94
|
+
size: "sm"
|
|
95
|
+
}), "px-4"),
|
|
96
|
+
onClick: () => {
|
|
97
|
+
onAppend(nextName);
|
|
98
|
+
setNextName("");
|
|
99
|
+
},
|
|
100
|
+
children: "New"
|
|
101
|
+
})]
|
|
102
|
+
})
|
|
103
|
+
]
|
|
86
104
|
});
|
|
87
105
|
}
|
|
88
106
|
function JsonInput({ fieldName }) {
|
|
@@ -142,12 +160,12 @@ function FieldInput({ field, fieldName, isRequired, ...props }) {
|
|
|
142
160
|
if (field.enum && field.enum.length > 0) {
|
|
143
161
|
const idx = field.enum.indexOf(value);
|
|
144
162
|
return /* @__PURE__ */ jsxs(Select, {
|
|
145
|
-
value: String(idx),
|
|
163
|
+
value: idx === -1 && isRequired ? "" : String(idx),
|
|
146
164
|
onValueChange: (v) => setValue(field.enum[Number(v)]),
|
|
147
165
|
children: [/* @__PURE__ */ jsx(SelectTrigger, {
|
|
148
166
|
id,
|
|
149
167
|
...props,
|
|
150
|
-
children: /* @__PURE__ */ jsx(SelectValue, {})
|
|
168
|
+
children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select" })
|
|
151
169
|
}), /* @__PURE__ */ jsxs(SelectContent, { children: [field.enum.map((item, i) => /* @__PURE__ */ jsx(SelectItem, {
|
|
152
170
|
value: String(i),
|
|
153
171
|
children: typeof item === "string" ? item : JSON.stringify(item, null, 2)
|
|
@@ -194,9 +212,10 @@ function FieldInput({ field, fieldName, isRequired, ...props }) {
|
|
|
194
212
|
}
|
|
195
213
|
function FieldSet({ field: _field, fieldName, toolbar, name, isRequired, depth = 0, slotType, collapsible = true, ...props }) {
|
|
196
214
|
const { readOnly, writeOnly } = useSchemaScope();
|
|
197
|
-
const
|
|
215
|
+
const { resolve, generateDefault, schemaToString } = useSchemaUtils();
|
|
216
|
+
const field = resolve(_field);
|
|
198
217
|
const [show, setShow] = useState(!collapsible);
|
|
199
|
-
const { info, updateInfo } = useFieldInfo(fieldName, field);
|
|
218
|
+
const { info, updateInfo } = useFieldInfo(fieldName, field, depth);
|
|
200
219
|
const id = stringifyFieldKey(fieldName);
|
|
201
220
|
const dataEngine = useDataEngine();
|
|
202
221
|
const [isDefined] = useFieldValue(fieldName, { compute(currentValue) {
|
|
@@ -212,7 +231,7 @@ function FieldSet({ field: _field, fieldName, toolbar, name, isRequired, depth =
|
|
|
212
231
|
type: "button",
|
|
213
232
|
className: cn(labelVariants(), "inline-flex items-center gap-1 font-mono me-auto"),
|
|
214
233
|
onClick: () => {
|
|
215
|
-
dataEngine.init(fieldName,
|
|
234
|
+
dataEngine.init(fieldName, generateDefault(schema));
|
|
216
235
|
setShow((prev) => !prev);
|
|
217
236
|
},
|
|
218
237
|
children: [
|
|
@@ -253,6 +272,7 @@ function FieldSet({ field: _field, fieldName, toolbar, name, isRequired, depth =
|
|
|
253
272
|
field: union[info.oneOf],
|
|
254
273
|
depth: depth + 1,
|
|
255
274
|
slotType: showSelect ? false : slotType,
|
|
275
|
+
collapsible,
|
|
256
276
|
toolbar: /* @__PURE__ */ jsxs(Fragment$1, { children: [showSelect && /* @__PURE__ */ jsx("select", {
|
|
257
277
|
className: "text-xs font-mono",
|
|
258
278
|
value: info.oneOf,
|
|
@@ -262,7 +282,7 @@ function FieldSet({ field: _field, fieldName, toolbar, name, isRequired, depth =
|
|
|
262
282
|
children: union.map((item, i) => /* @__PURE__ */ jsx("option", {
|
|
263
283
|
value: i,
|
|
264
284
|
className: "bg-fd-popover text-fd-popover-foreground",
|
|
265
|
-
children: schemaToString(item,
|
|
285
|
+
children: schemaToString(item, FormatFlags.UseAlias)
|
|
266
286
|
}, i))
|
|
267
287
|
}), toolbar] })
|
|
268
288
|
});
|
|
@@ -278,6 +298,7 @@ function FieldSet({ field: _field, fieldName, toolbar, name, isRequired, depth =
|
|
|
278
298
|
...field,
|
|
279
299
|
type: info.selectedType
|
|
280
300
|
},
|
|
301
|
+
collapsible,
|
|
281
302
|
depth: depth + 1,
|
|
282
303
|
slotType: showSelect ? false : slotType,
|
|
283
304
|
toolbar: /* @__PURE__ */ jsxs(Fragment$1, { children: [showSelect && /* @__PURE__ */ jsx("select", {
|
|
@@ -298,6 +319,7 @@ function FieldSet({ field: _field, fieldName, toolbar, name, isRequired, depth =
|
|
|
298
319
|
const schema = info.intersection?.merged ?? field;
|
|
299
320
|
return /* @__PURE__ */ jsxs("fieldset", {
|
|
300
321
|
...props,
|
|
322
|
+
"data-collapsible": collapsible,
|
|
301
323
|
className: cn("flex flex-col gap-1.5 col-span-full @container", props.className),
|
|
302
324
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
303
325
|
className: fieldLabelVariants(),
|
|
@@ -316,6 +338,7 @@ function FieldSet({ field: _field, fieldName, toolbar, name, isRequired, depth =
|
|
|
316
338
|
}
|
|
317
339
|
if (field.type === "array") return /* @__PURE__ */ jsxs("fieldset", {
|
|
318
340
|
...props,
|
|
341
|
+
"data-collapsible": collapsible,
|
|
319
342
|
className: cn("flex flex-col gap-1.5 col-span-full", props.className),
|
|
320
343
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
321
344
|
className: fieldLabelVariants(),
|
|
@@ -352,7 +375,8 @@ function FieldSet({ field: _field, fieldName, toolbar, name, isRequired, depth =
|
|
|
352
375
|
}
|
|
353
376
|
function ArrayInput({ fieldName, items: itemSchema, ...props }) {
|
|
354
377
|
const name = fieldName.at(-1) ?? "";
|
|
355
|
-
const {
|
|
378
|
+
const { generateDefault } = useSchemaUtils();
|
|
379
|
+
const { items, insertItem, removeItem } = useArray(fieldName);
|
|
356
380
|
return /* @__PURE__ */ jsxs("div", {
|
|
357
381
|
...props,
|
|
358
382
|
className: cn("flex flex-col gap-2", props.className),
|
|
@@ -387,7 +411,7 @@ function ArrayInput({ fieldName, items: itemSchema, ...props }) {
|
|
|
387
411
|
size: "sm"
|
|
388
412
|
})),
|
|
389
413
|
onClick: () => {
|
|
390
|
-
insertItem(
|
|
414
|
+
insertItem(generateDefault(itemSchema));
|
|
391
415
|
},
|
|
392
416
|
children: [/* @__PURE__ */ jsx(Plus, { className: "size-4" }), "New Item"]
|
|
393
417
|
})]
|
|
@@ -21,6 +21,6 @@ declare function APIPlayground({
|
|
|
21
21
|
path,
|
|
22
22
|
method,
|
|
23
23
|
ctx
|
|
24
|
-
}: APIPlaygroundProps): Promise<string | number | bigint | boolean | Iterable<react.ReactNode> |
|
|
24
|
+
}: APIPlaygroundProps): Promise<string | number | bigint | boolean | react_jsx_runtime0.JSX.Element | Iterable<react.ReactNode> | null | undefined>;
|
|
25
25
|
//#endregion
|
|
26
26
|
export { APIPlayground, APIPlaygroundProps, ParameterField, SecurityEntry };
|
package/dist/playground/index.js
CHANGED
|
@@ -40,7 +40,7 @@ function writeReferences(schema, ctx, stack = /* @__PURE__ */ new WeakMap()) {
|
|
|
40
40
|
const out = stack.get(schema);
|
|
41
41
|
const id = ctx.nextId();
|
|
42
42
|
ctx.references[id] = out;
|
|
43
|
-
return { $ref: id };
|
|
43
|
+
return { $ref: `#/${id}` };
|
|
44
44
|
}
|
|
45
45
|
const output = { ...schema };
|
|
46
46
|
stack.set(schema, output);
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { getDefaultValue } from "./get-default-values.js";
|
|
2
1
|
import { mergeAllOf } from "../utils/merge-schema.js";
|
|
2
|
+
import { schemaToString } from "../utils/schema-to-string.js";
|
|
3
3
|
import { createContext, use, useMemo } from "react";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
import { Ajv2020 } from "ajv/dist/2020";
|
|
6
|
-
import { useDataEngine, useFieldValue } from "@fumari/stf";
|
|
6
|
+
import { useDataEngine, useFieldValue, useNamespace } from "@fumari/stf";
|
|
7
7
|
import { stringifyFieldKey } from "@fumari/stf/lib/utils";
|
|
8
|
+
import { sample } from "openapi-sampler";
|
|
8
9
|
|
|
9
10
|
//#region src/playground/schema.tsx
|
|
10
11
|
const SchemaContext = createContext(void 0);
|
|
@@ -51,33 +52,37 @@ function useSchemaScope() {
|
|
|
51
52
|
* @param schema - The JSON Schema to generate initial values.
|
|
52
53
|
* @param depth - The depth to avoid duplicated field name with same schema (e.g. nested `oneOf`).
|
|
53
54
|
*/
|
|
54
|
-
function useFieldInfo(fieldName, schema) {
|
|
55
|
+
function useFieldInfo(fieldName, schema, depth = 0) {
|
|
55
56
|
const { ajv } = use(SchemaContext);
|
|
56
57
|
const engine = useDataEngine();
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
if (
|
|
65
|
-
|
|
58
|
+
const { generateDefault } = useSchemaUtils();
|
|
59
|
+
const [info, setInfo] = useFieldValue([], { stf: useNamespace({
|
|
60
|
+
namespace: `field-info:${depth}:${stringifyFieldKey(fieldName)}`,
|
|
61
|
+
initial() {
|
|
62
|
+
const value = engine.get(fieldName);
|
|
63
|
+
const out = { oneOf: -1 };
|
|
64
|
+
const union = getUnion(schema);
|
|
65
|
+
if (union) {
|
|
66
|
+
const [members, field] = union;
|
|
67
|
+
out.oneOf = members.findIndex((item) => ajv.validate(item, value));
|
|
68
|
+
if (out.oneOf === -1) out.oneOf = 0;
|
|
69
|
+
out.unionField = field;
|
|
70
|
+
}
|
|
71
|
+
if (Array.isArray(schema.type)) {
|
|
72
|
+
const types = schema.type;
|
|
73
|
+
out.selectedType = types.find((type) => {
|
|
74
|
+
return ajv.validate({
|
|
75
|
+
...schema,
|
|
76
|
+
type
|
|
77
|
+
}, value);
|
|
78
|
+
}) ?? types[0];
|
|
79
|
+
}
|
|
80
|
+
if (schema.allOf) {
|
|
81
|
+
const merged = mergeAllOf(schema);
|
|
82
|
+
if (typeof merged !== "boolean") out.intersection = { merged };
|
|
83
|
+
}
|
|
84
|
+
return out;
|
|
66
85
|
}
|
|
67
|
-
if (Array.isArray(schema.type)) {
|
|
68
|
-
const types = schema.type;
|
|
69
|
-
out.selectedType = types.find((type) => {
|
|
70
|
-
schema.type = type;
|
|
71
|
-
const match = ajv.validate(schema, value);
|
|
72
|
-
schema.type = types;
|
|
73
|
-
return match;
|
|
74
|
-
}) ?? types.at(0);
|
|
75
|
-
}
|
|
76
|
-
if (schema.allOf) {
|
|
77
|
-
const merged = mergeAllOf(schema);
|
|
78
|
-
if (typeof merged !== "boolean") out.intersection = { merged };
|
|
79
|
-
}
|
|
80
|
-
return out;
|
|
81
86
|
}) });
|
|
82
87
|
return {
|
|
83
88
|
info,
|
|
@@ -94,20 +99,37 @@ function useFieldInfo(fieldName, schema) {
|
|
|
94
99
|
...schema,
|
|
95
100
|
type: updated.selectedType
|
|
96
101
|
};
|
|
97
|
-
engine.update(fieldName,
|
|
102
|
+
engine.update(fieldName, generateDefault(valueSchema));
|
|
98
103
|
}
|
|
99
104
|
};
|
|
100
105
|
}
|
|
101
|
-
|
|
102
|
-
* Resolve `$ref` in the schema, **not recursive**.
|
|
103
|
-
*/
|
|
104
|
-
function useResolvedSchema(schema) {
|
|
106
|
+
function useSchemaUtils() {
|
|
105
107
|
const { references } = use(SchemaContext);
|
|
106
|
-
|
|
108
|
+
function resolve(schema) {
|
|
107
109
|
if (typeof schema === "boolean") return anyFields;
|
|
108
|
-
|
|
110
|
+
let ref = schema.$ref;
|
|
111
|
+
if (ref) {
|
|
112
|
+
if (ref.startsWith("#/")) ref = ref.slice(2);
|
|
113
|
+
if (ref in references) return fallbackAny(references[ref]);
|
|
114
|
+
}
|
|
109
115
|
return schema;
|
|
110
|
-
}
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
generateDefault(schema) {
|
|
119
|
+
return sample(schema, {
|
|
120
|
+
skipNonRequired: true,
|
|
121
|
+
skipReadOnly: true,
|
|
122
|
+
quiet: true
|
|
123
|
+
}, references);
|
|
124
|
+
},
|
|
125
|
+
resolve,
|
|
126
|
+
schemaToString(value, flags) {
|
|
127
|
+
return schemaToString(value, (s) => ({
|
|
128
|
+
dereferenced: resolve(s),
|
|
129
|
+
raw: s
|
|
130
|
+
}), flags);
|
|
131
|
+
}
|
|
132
|
+
};
|
|
111
133
|
}
|
|
112
134
|
function fallbackAny(schema) {
|
|
113
135
|
return typeof schema === "boolean" ? anyFields : schema;
|
|
@@ -118,4 +140,4 @@ function getUnion(schema) {
|
|
|
118
140
|
}
|
|
119
141
|
|
|
120
142
|
//#endregion
|
|
121
|
-
export { SchemaProvider, anyFields, useFieldInfo,
|
|
143
|
+
export { SchemaProvider, anyFields, useFieldInfo, useSchemaScope, useSchemaUtils };
|
|
@@ -10,7 +10,7 @@ const SelectGroup = SelectPrimitive.Group;
|
|
|
10
10
|
const SelectValue = SelectPrimitive.Value;
|
|
11
11
|
const SelectTrigger = forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(SelectPrimitive.Trigger, {
|
|
12
12
|
ref,
|
|
13
|
-
className: cn("flex items-center w-full rounded-md border p-2 gap-2 text-start text-sm text-fd-secondary-foreground bg-fd-secondary hover:bg-fd-accent focus:outline-none focus:ring focus:ring-fd-ring disabled:cursor-not-allowed disabled:opacity-50", className),
|
|
13
|
+
className: cn("flex items-center w-full rounded-md border p-2 gap-2 text-start text-sm text-fd-secondary-foreground bg-fd-secondary hover:bg-fd-accent focus:outline-none focus:ring focus:ring-fd-ring disabled:cursor-not-allowed disabled:opacity-50 data-placeholder:text-fd-muted-foreground", className),
|
|
14
14
|
...props,
|
|
15
15
|
children: [children, /* @__PURE__ */ jsx(SelectPrimitive.Icon, {
|
|
16
16
|
asChild: true,
|
package/dist/ui/full.js
CHANGED
|
@@ -10,8 +10,8 @@ function createAPIPage(server, options = {}) {
|
|
|
10
10
|
...options,
|
|
11
11
|
shiki: configDefault,
|
|
12
12
|
generateTypeScriptSchema(method, statusCode, contentType, ctx) {
|
|
13
|
-
const schema = method.responses?.[statusCode]?.content?.[contentType];
|
|
14
|
-
if (!schema) return;
|
|
13
|
+
const schema = method.responses?.[statusCode]?.content?.[contentType].schema;
|
|
14
|
+
if (!schema || typeof schema !== "object") return;
|
|
15
15
|
return getTypescriptSchema(schema, ctx);
|
|
16
16
|
}
|
|
17
17
|
});
|
|
@@ -4,8 +4,8 @@ import { MethodLabel } from "../components/method-label.js";
|
|
|
4
4
|
import { encodeRequestData } from "../../requests/media/encode.js";
|
|
5
5
|
import { AccordionContent, AccordionHeader, AccordionItem, AccordionTrigger, Accordions } from "../components/accordion.js";
|
|
6
6
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
-
import { Tabs, TabsContent, TabsList, TabsTrigger } from "fumadocs-ui/components/tabs";
|
|
8
7
|
import { sample } from "openapi-sampler";
|
|
8
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from "fumadocs-ui/components/tabs";
|
|
9
9
|
|
|
10
10
|
//#region src/ui/operation/request-tabs.tsx
|
|
11
11
|
function getExampleRequests(path, operation, ctx) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { getPreferredType } from "../../utils/schema.js";
|
|
2
2
|
import { AccordionContent, AccordionHeader, AccordionItem, AccordionTrigger, Accordions } from "../components/accordion.js";
|
|
3
3
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
-
import { Tab, Tabs } from "fumadocs-ui/components/tabs";
|
|
5
4
|
import { sample } from "openapi-sampler";
|
|
5
|
+
import { Tab, Tabs } from "fumadocs-ui/components/tabs";
|
|
6
6
|
|
|
7
7
|
//#region src/ui/operation/response-tabs.tsx
|
|
8
8
|
function ResponseTabs({ operation, ctx }) {
|
package/dist/ui/schema/client.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import { cn } from "../../utils/cn.js";
|
|
4
4
|
import { Badge } from "../components/method-label.js";
|
|
5
|
-
import { Fragment, createContext, use, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
5
|
+
import { Fragment, Suspense, createContext, use, useCallback, useDeferredValue, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
6
6
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
-
import { ChevronDown } from "lucide-react";
|
|
7
|
+
import { ChevronDown, FilterIcon } from "lucide-react";
|
|
8
8
|
import { cva } from "class-variance-authority";
|
|
9
9
|
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "fumadocs-ui/components/ui/collapsible";
|
|
10
10
|
import { buttonVariants } from "fumadocs-ui/components/ui/button";
|
|
@@ -58,11 +58,7 @@ function SchemaUIProperty({ name, $type, variant = "default", overrides }) {
|
|
|
58
58
|
$ref: $type
|
|
59
59
|
});
|
|
60
60
|
} else if (schema.type === "object" && schema.props.length > 0) {
|
|
61
|
-
if (variant === "expand") return
|
|
62
|
-
name: prop.name,
|
|
63
|
-
$type: prop.$type,
|
|
64
|
-
overrides: { required: prop.required }
|
|
65
|
-
}, prop.name));
|
|
61
|
+
if (variant === "expand") return /* @__PURE__ */ jsx(SearchProps, { props: schema.props });
|
|
66
62
|
type = renderRef({
|
|
67
63
|
pathName: name,
|
|
68
64
|
$ref: $type
|
|
@@ -103,6 +99,30 @@ function SchemaUIProperty({ name, $type, variant = "default", overrides }) {
|
|
|
103
99
|
children: child
|
|
104
100
|
});
|
|
105
101
|
}
|
|
102
|
+
function SearchProps({ props }) {
|
|
103
|
+
const [search, setSearch] = useState("");
|
|
104
|
+
const deferredValue = useDeferredValue(search);
|
|
105
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("div", {
|
|
106
|
+
className: "flex items-center border my-2 rounded-md bg-fd-secondary text-fd-secondary-foreground transition-colors shadow-sm focus-within:ring-2 focus-within:ring-fd-ring",
|
|
107
|
+
children: [/* @__PURE__ */ jsx(FilterIcon, { className: "text-fd-muted-foreground ms-2 size-3.5" }), /* @__PURE__ */ jsx("input", {
|
|
108
|
+
value: search,
|
|
109
|
+
onChange: (e) => setSearch(e.target.value),
|
|
110
|
+
placeholder: "Filter Properties",
|
|
111
|
+
className: "text-sm ps-2 py-2 flex-1 outline-none placeholder:text-fd-muted-foreground"
|
|
112
|
+
})]
|
|
113
|
+
}), /* @__PURE__ */ jsx(Suspense, { children: /* @__PURE__ */ jsx(SearchPropsContent, {
|
|
114
|
+
search: deferredValue,
|
|
115
|
+
props
|
|
116
|
+
}) })] });
|
|
117
|
+
}
|
|
118
|
+
function SearchPropsContent({ search, props }) {
|
|
119
|
+
search = search.trim().toLowerCase();
|
|
120
|
+
return (search.length > 0 ? props.filter((prop) => prop.name.toLowerCase().includes(search)) : props).map((prop) => /* @__PURE__ */ jsx(SchemaUIProperty, {
|
|
121
|
+
name: prop.name,
|
|
122
|
+
$type: prop.$type,
|
|
123
|
+
overrides: { required: prop.required }
|
|
124
|
+
}, prop.name));
|
|
125
|
+
}
|
|
106
126
|
function InfoTag({ tag }) {
|
|
107
127
|
const ref = useRef(null);
|
|
108
128
|
const [isTruncated, setTruncated] = useState(false);
|
|
@@ -138,12 +158,15 @@ function InfoTag({ tag }) {
|
|
|
138
158
|
function SchemaUIPopover({ initialPath }) {
|
|
139
159
|
const [path, setPath] = useState(initialPath);
|
|
140
160
|
const ref = useRef(null);
|
|
141
|
-
|
|
142
|
-
|
|
161
|
+
useLayoutEffect(() => {
|
|
162
|
+
const last = path[0];
|
|
143
163
|
const element = ref.current;
|
|
144
|
-
if (!element || !element.parentElement) return;
|
|
145
|
-
element.parentElement.scrollTop = 0;
|
|
146
|
-
|
|
164
|
+
if (!element || !last || !element.parentElement) return;
|
|
165
|
+
element.parentElement.scrollTop = last?.scrollTop ?? 0;
|
|
166
|
+
return () => {
|
|
167
|
+
last.scrollTop = element.parentElement.scrollTop;
|
|
168
|
+
};
|
|
169
|
+
}, [path]);
|
|
147
170
|
const context = useMemo(() => ({ renderTrigger: ({ $ref, pathName, children }) => /* @__PURE__ */ jsx("button", {
|
|
148
171
|
className: cn(typeVariants({ variant: "trigger" })),
|
|
149
172
|
onClick: () => setPath((path) => [...path, {
|
|
@@ -152,9 +175,9 @@ function SchemaUIPopover({ initialPath }) {
|
|
|
152
175
|
}]),
|
|
153
176
|
children
|
|
154
177
|
}) }), []);
|
|
155
|
-
|
|
178
|
+
const currentRef = path.findLast((item) => item.$ref !== void 0);
|
|
156
179
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
|
|
157
|
-
className: "sticky top-0 flex flex-row flex-wrap items-center text-sm font-medium font-mono bg-fd-
|
|
180
|
+
className: "sticky top-0 flex flex-row flex-wrap items-center text-sm font-medium font-mono bg-fd-popover px-2 py-1.5 border-b",
|
|
158
181
|
children: path.map((item, i) => {
|
|
159
182
|
const className = cn(path.some((other, j) => j < i && other.$ref === item.$ref) && "text-orange-400", item.$ref && "hover:underline hover:text-fd-accent-foreground");
|
|
160
183
|
const node = item.$ref ? /* @__PURE__ */ jsx("button", {
|
|
@@ -169,12 +192,12 @@ function SchemaUIPopover({ initialPath }) {
|
|
|
169
192
|
})
|
|
170
193
|
}), /* @__PURE__ */ jsx(PopoverContext, {
|
|
171
194
|
value: context,
|
|
172
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
195
|
+
children: currentRef?.$ref && /* @__PURE__ */ jsx("div", {
|
|
173
196
|
ref,
|
|
174
197
|
className: "px-2",
|
|
175
198
|
children: /* @__PURE__ */ jsx(SchemaUIProperty, {
|
|
176
199
|
name: "",
|
|
177
|
-
$type:
|
|
200
|
+
$type: currentRef.$ref,
|
|
178
201
|
variant: "expand"
|
|
179
202
|
})
|
|
180
203
|
})
|
|
@@ -217,7 +240,7 @@ function useRenderRef() {
|
|
|
217
240
|
function RootPopoverTrigger({ $ref, pathName, children }) {
|
|
218
241
|
const ref = useCallback((element) => {
|
|
219
242
|
if (!element || element.style.getPropertyValue("--initial-height")) return;
|
|
220
|
-
element.style.setProperty("--initial-height", `${element.clientHeight}px`);
|
|
243
|
+
element.style.setProperty("--initial-height", `${element.clientHeight + 2}px`);
|
|
221
244
|
}, []);
|
|
222
245
|
return /* @__PURE__ */ jsxs(Popover, { children: [/* @__PURE__ */ jsx(PopoverTrigger, {
|
|
223
246
|
className: cn(typeVariants({ variant: "trigger" })),
|
|
@@ -16,15 +16,16 @@ interface InfoTag {
|
|
|
16
16
|
label: string;
|
|
17
17
|
value: string;
|
|
18
18
|
}
|
|
19
|
+
interface SchemaDataObjectProperty {
|
|
20
|
+
name: string;
|
|
21
|
+
$type: string;
|
|
22
|
+
required: boolean;
|
|
23
|
+
}
|
|
19
24
|
type SchemaData = FieldBase & ({
|
|
20
25
|
type: 'primitive';
|
|
21
26
|
} | {
|
|
22
27
|
type: 'object';
|
|
23
|
-
props:
|
|
24
|
-
name: string;
|
|
25
|
-
$type: string;
|
|
26
|
-
required: boolean;
|
|
27
|
-
}[];
|
|
28
|
+
props: SchemaDataObjectProperty[];
|
|
28
29
|
} | {
|
|
29
30
|
type: 'array';
|
|
30
31
|
item: {
|
package/dist/ui/schema/index.js
CHANGED
|
@@ -198,7 +198,7 @@ function generateSchemaUI({ root, readOnly, writeOnly }, ctx) {
|
|
|
198
198
|
required: schema.required?.includes(key) ?? false
|
|
199
199
|
});
|
|
200
200
|
}
|
|
201
|
-
if (additionalProperties
|
|
201
|
+
if (additionalProperties && isVisible(additionalProperties)) {
|
|
202
202
|
const $type = getSchemaId(additionalProperties);
|
|
203
203
|
scanRefs($type, additionalProperties);
|
|
204
204
|
out.props.push({
|
|
@@ -4,7 +4,14 @@ let FormatFlags = /* @__PURE__ */ function(FormatFlags) {
|
|
|
4
4
|
FormatFlags[FormatFlags["UseAlias"] = 1] = "UseAlias";
|
|
5
5
|
return FormatFlags;
|
|
6
6
|
}({});
|
|
7
|
-
function schemaToString(value,
|
|
7
|
+
function schemaToString(value, _resolver, flags = FormatFlags.None) {
|
|
8
|
+
const resolver = typeof _resolver === "function" ? _resolver : (schema) => {
|
|
9
|
+
const ref = _resolver?.getRawRef(schema);
|
|
10
|
+
return {
|
|
11
|
+
dereferenced: schema,
|
|
12
|
+
raw: ref ? { $ref: ref } : void 0
|
|
13
|
+
};
|
|
14
|
+
};
|
|
8
15
|
function union(union, sep, flags) {
|
|
9
16
|
const members = /* @__PURE__ */ new Set();
|
|
10
17
|
let nullable = false;
|
|
@@ -17,11 +24,13 @@ function schemaToString(value, ctx, flags = FormatFlags.None) {
|
|
|
17
24
|
return nullable ? `${result} | null` : result;
|
|
18
25
|
}
|
|
19
26
|
function run(schema, flags) {
|
|
27
|
+
const resolved = resolver(schema);
|
|
28
|
+
schema = resolved.dereferenced;
|
|
20
29
|
if (schema === true) return "any";
|
|
21
30
|
else if (schema === false) return "never";
|
|
22
31
|
if ((flags & FormatFlags.UseAlias) === FormatFlags.UseAlias) {
|
|
23
32
|
if (schema.title) return schema.title;
|
|
24
|
-
const ref =
|
|
33
|
+
const ref = resolved.raw?.$ref?.split("/");
|
|
25
34
|
if (ref && ref.length > 0) return ref[ref.length - 1];
|
|
26
35
|
}
|
|
27
36
|
if (Array.isArray(schema.type)) return union(schema.type.map((type) => ({
|
package/dist/utils/schema.d.ts
CHANGED
|
@@ -6,7 +6,9 @@ type NoReference<T> = T extends (infer I)[] ? NoReference<I>[] : T extends Refer
|
|
|
6
6
|
type NoReferenceJSONSchema<T> = T extends (infer I)[] ? NoReference<I>[] : T extends {
|
|
7
7
|
$ref?: string;
|
|
8
8
|
} ? Omit<T, '$ref'> : T;
|
|
9
|
-
type ParsedSchema = JSONSchema
|
|
9
|
+
type ParsedSchema = JSONSchema & {
|
|
10
|
+
'x-playground-lazy'?: boolean;
|
|
11
|
+
};
|
|
10
12
|
type ResolvedSchema = NoReferenceJSONSchema<ParsedSchema>;
|
|
11
13
|
//#endregion
|
|
12
14
|
export { NoReference, ParsedSchema, ResolvedSchema };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fumadocs-openapi",
|
|
3
|
-
"version": "10.3.
|
|
3
|
+
"version": "10.3.12",
|
|
4
4
|
"description": "Generate MDX docs for your OpenAPI spec",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Docs",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"remark-rehype": "^11.1.2",
|
|
78
78
|
"tailwind-merge": "^3.4.1",
|
|
79
79
|
"xml-js": "^1.6.11",
|
|
80
|
-
"@fumari/stf": "1.0.
|
|
80
|
+
"@fumari/stf": "1.0.2"
|
|
81
81
|
},
|
|
82
82
|
"devDependencies": {
|
|
83
83
|
"@scalar/api-client-react": "^1.3.96",
|
|
@@ -90,8 +90,8 @@
|
|
|
90
90
|
"tsdown": "^0.20.3",
|
|
91
91
|
"@fumadocs/tailwind": "0.0.2",
|
|
92
92
|
"eslint-config-custom": "0.0.0",
|
|
93
|
-
"fumadocs-core": "16.6.
|
|
94
|
-
"fumadocs-ui": "16.6.
|
|
93
|
+
"fumadocs-core": "16.6.6",
|
|
94
|
+
"fumadocs-ui": "16.6.6",
|
|
95
95
|
"tsconfig": "0.0.0"
|
|
96
96
|
},
|
|
97
97
|
"peerDependencies": {
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
//#region src/playground/get-default-values.ts
|
|
2
|
-
function getDefaultValue(schema) {
|
|
3
|
-
if (typeof schema === "boolean") return null;
|
|
4
|
-
const type = schema.type;
|
|
5
|
-
if (Array.isArray(type)) return getDefaultValue({
|
|
6
|
-
...schema,
|
|
7
|
-
type: type[0]
|
|
8
|
-
});
|
|
9
|
-
if (type === "object" && typeof schema === "object") return Object.fromEntries(Object.entries(schema.properties ?? {}).map(([key, prop]) => {
|
|
10
|
-
return [key, getDefaultValue(prop)];
|
|
11
|
-
}));
|
|
12
|
-
if (type === "array") return [];
|
|
13
|
-
if (type === "null") return null;
|
|
14
|
-
if (type === "string") {
|
|
15
|
-
if (typeof schema === "object" && schema.format === "binary") return void 0;
|
|
16
|
-
return "";
|
|
17
|
-
}
|
|
18
|
-
if (type === "number" || type === "integer") return 0;
|
|
19
|
-
if (type === "boolean") return false;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
//#endregion
|
|
23
|
-
export { getDefaultValue };
|