fumadocs-openapi 9.5.0 → 9.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/playground/client.d.ts.map +1 -1
- package/dist/playground/client.js +36 -64
- package/dist/playground/inputs.d.ts.map +1 -1
- package/dist/playground/inputs.js +24 -17
- package/dist/playground/schema.d.ts.map +1 -1
- package/dist/playground/schema.js +27 -27
- package/dist/render/operation/index.js +6 -8
- package/dist/render/renderer.d.ts +1 -1
- package/dist/render/renderer.d.ts.map +1 -1
- package/dist/render/schema/client.d.ts +18 -0
- package/dist/render/schema/client.d.ts.map +1 -0
- package/dist/render/schema/client.js +139 -0
- package/dist/render/schema/index.d.ts +7 -0
- package/dist/render/schema/index.d.ts.map +1 -0
- package/dist/render/schema/index.js +11 -0
- package/dist/render/schema/server.d.ts +43 -0
- package/dist/render/schema/server.d.ts.map +1 -0
- package/dist/render/schema/server.js +206 -0
- package/dist/render/schema/ui.d.ts +16 -0
- package/dist/render/schema/ui.d.ts.map +1 -0
- package/dist/render/schema/ui.js +14 -0
- package/dist/server/create.d.ts +11 -0
- package/dist/server/create.d.ts.map +1 -1
- package/dist/ui/components/method-label.d.ts +1 -1
- package/dist/ui/contexts/code-example.d.ts +4 -1
- package/dist/ui/contexts/code-example.d.ts.map +1 -1
- package/dist/ui/contexts/code-example.js +1 -1
- package/dist/ui/index.d.ts +3 -7
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +2 -13
- package/dist/utils/schema-to-string.d.ts +5 -1
- package/dist/utils/schema-to-string.d.ts.map +1 -1
- package/dist/utils/schema-to-string.js +25 -24
- package/package.json +11 -11
- package/dist/render/schema.d.ts +0 -13
- package/dist/render/schema.d.ts.map +0 -1
- package/dist/render/schema.js +0 -239
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/playground/client.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,EAAE,EAEP,KAAK,cAAc,EAEnB,KAAK,YAAY,EAKlB,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EACV,oBAAoB,EACpB,qBAAqB,EACrB,SAAS,EACT,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/playground/client.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,EAAE,EAEP,KAAK,cAAc,EAEnB,KAAK,YAAY,EAKlB,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EACV,oBAAoB,EACpB,qBAAqB,EACrB,SAAS,EACT,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;AAUzB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EACb,aAAa,EACd,MAAM,oBAAoB,CAAC;AAiB5B,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAuBzE,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,IAAI,EAAE,OAAO,CAAC;IAEd,QAAQ,CAAC,EAAE,WAAW,CAAC;CACxB;AAED,MAAM,WAAW,WAAW,CAAC,KAAK,SAAS,SAAS,CAAC,UAAU,CAAC,EAAE,IAAI;IACpE,MAAM,EAAE,CAAC,KAAK,EAAE;QACd;;WAEG;QACH,IAAI,EAAE,IAAI,CAAC;QACX,KAAK,EAAE,qBAAqB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAChD,UAAU,EAAE,oBAAoB,CAAC;QACjC,SAAS,EAAE,kBAAkB,CAAC,UAAU,CAAC,CAAC;KAC3C,KAAK,YAAY,CAAC;CACpB;AAED,MAAM,WAAW,WAAY,SAAQ,cAAc,CAAC,eAAe,CAAC;IAClE,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;IAC9B,UAAU,EAAE,aAAa,EAAE,EAAE,CAAC;IAC9B,IAAI,CAAC,EAAE;QACL,MAAM,EAAE,aAAa,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE;QACP,SAAS,CAAC,EAAE,WAAW,CACrB,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,MAAM,EAAE,EACnC,cAAc,CACf,CAAC;QACF,IAAI,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,aAAa,CAAC,CAAC;QACzD,IAAI,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;KAC3C,CAAC;IAEF,UAAU,CAAC,EAAE,OAAO,CAAC;QACnB,aAAa,EAAE,EAAE,CAAC;YAAE,IAAI,EAAE,WAAW,CAAA;SAAE,CAAC,CAAC;KAC1C,CAAC,CAAC;CACJ;AAgBD,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,EAC7B,KAAK,EACL,MAAc,EACd,UAAU,EACV,UAAe,EACf,IAAI,EACJ,MAAM,EACN,UAAU,EACV,QAAQ,EACR,UAAU,EAAE,EAAE,aAAoC,EAAO,EACzD,cAAmB,EACnB,GAAG,IAAI,EACR,EAAE,WAAW,2CA0Kb"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { Fragment, lazy, useEffect, useMemo, useState, } from 'react';
|
|
4
|
-
import { Controller, FormProvider, useForm, useFormContext, } from 'react-hook-form';
|
|
4
|
+
import { Controller, FormProvider, get, set, useForm, useFormContext, } from 'react-hook-form';
|
|
5
5
|
import { useApiContext, useServerSelectContext } from '../ui/contexts/api.js';
|
|
6
6
|
import { FieldInput, FieldSet, JsonInput, ObjectInput } from './inputs.js';
|
|
7
7
|
import { getStatusInfo } from './status-info.js';
|
|
@@ -17,7 +17,6 @@ import { cn } from 'fumadocs-ui/utils/cn';
|
|
|
17
17
|
import { SchemaProvider, useResolvedSchema, } from '../playground/schema.js';
|
|
18
18
|
import { useRequestDataUpdater, useRequestInitialData, } from '../ui/contexts/code-example.js';
|
|
19
19
|
import { useEffectEvent } from 'fumadocs-core/utils/use-effect-event';
|
|
20
|
-
import { useOnChange } from 'fumadocs-core/utils/use-on-change';
|
|
21
20
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '../ui/components/select.js';
|
|
22
21
|
import { labelVariants } from '../ui/components/input.js';
|
|
23
22
|
const AuthPrefix = '__fumadocs_auth';
|
|
@@ -30,7 +29,7 @@ const OauthDialogTrigger = lazy(() => import('./auth/oauth-dialog.js').then((mod
|
|
|
30
29
|
})));
|
|
31
30
|
export default function Client({ route, method = 'GET', securities, parameters = [], body, fields, references, proxyUrl, components: { ResultDisplay = DefaultResultDisplay } = {}, requestTimeout = 10, ...rest }) {
|
|
32
31
|
const { server } = useServerSelectContext();
|
|
33
|
-
const requestData = useRequestInitialData();
|
|
32
|
+
const { key: requestDataKey, data: requestData } = useRequestInitialData();
|
|
34
33
|
const updater = useRequestDataUpdater();
|
|
35
34
|
const fieldInfoMap = useMemo(() => new Map(), []);
|
|
36
35
|
const { mediaAdapters } = useApiContext();
|
|
@@ -54,40 +53,13 @@ export default function Client({ route, method = 'GET', securities, parameters =
|
|
|
54
53
|
...input._encoded,
|
|
55
54
|
});
|
|
56
55
|
});
|
|
57
|
-
|
|
58
|
-
for (const item of inputs) {
|
|
59
|
-
manipulateValues(values, item.fieldName, () => {
|
|
60
|
-
const stored = localStorage.getItem(AuthPrefix + item.original.id);
|
|
61
|
-
if (stored) {
|
|
62
|
-
const parsed = JSON.parse(stored);
|
|
63
|
-
if (typeof parsed === typeof item.defaultValue)
|
|
64
|
-
return parsed;
|
|
65
|
-
}
|
|
66
|
-
return item.defaultValue;
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
return values;
|
|
70
|
-
}
|
|
71
|
-
useOnChange(defaultValues, () => {
|
|
56
|
+
const onUpdateDefaults = useEffectEvent(() => {
|
|
72
57
|
fieldInfoMap.clear();
|
|
73
58
|
form.reset(initAuthValues(defaultValues, inputs));
|
|
74
59
|
});
|
|
75
|
-
useOnChange(inputs, (current, previous) => {
|
|
76
|
-
form.reset((values) => {
|
|
77
|
-
for (const item of previous) {
|
|
78
|
-
if (current.some(({ original }) => original.id === item.original.id)) {
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
manipulateValues(values, item.fieldName, () => undefined);
|
|
82
|
-
}
|
|
83
|
-
return initAuthValues(values, current);
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
60
|
const onUpdateDebounced = useEffectEvent((values) => {
|
|
87
61
|
for (const item of inputs) {
|
|
88
|
-
const value = item.fieldName
|
|
89
|
-
.split('.')
|
|
90
|
-
.reduce((v, seg) => v[seg], values);
|
|
62
|
+
const value = get(values, item.fieldName);
|
|
91
63
|
if (value) {
|
|
92
64
|
localStorage.setItem(AuthPrefix + item.original.id, JSON.stringify(value));
|
|
93
65
|
}
|
|
@@ -100,6 +72,9 @@ export default function Client({ route, method = 'GET', securities, parameters =
|
|
|
100
72
|
values._encoded ?? (values._encoded = encodeRequestData(data, mediaAdapters, parameters));
|
|
101
73
|
updater.setData(data, values._encoded);
|
|
102
74
|
});
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
onUpdateDefaults();
|
|
77
|
+
}, [requestDataKey]);
|
|
103
78
|
useEffect(() => {
|
|
104
79
|
let timer = null;
|
|
105
80
|
const subscription = form.subscribe({
|
|
@@ -114,10 +89,21 @@ export default function Client({ route, method = 'GET', securities, parameters =
|
|
|
114
89
|
timer = window.setTimeout(() => onUpdateDebounced(values), timer ? 400 : 0);
|
|
115
90
|
},
|
|
116
91
|
});
|
|
117
|
-
form.reset((values) => initAuthValues(values, inputs));
|
|
118
92
|
return () => subscription();
|
|
119
93
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- mounted once only
|
|
120
94
|
}, []);
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
form.reset((values) => initAuthValues(values, inputs));
|
|
97
|
+
return () => {
|
|
98
|
+
form.reset((values) => {
|
|
99
|
+
for (const item of inputs) {
|
|
100
|
+
set(values, item.fieldName, undefined);
|
|
101
|
+
}
|
|
102
|
+
return values;
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- mounted once only
|
|
106
|
+
}, [inputs]);
|
|
121
107
|
const onSubmit = form.handleSubmit((value) => {
|
|
122
108
|
testQuery.start(mapInputs(value));
|
|
123
109
|
});
|
|
@@ -185,35 +171,6 @@ function BodyInput({ field: _field }) {
|
|
|
185
171
|
className: 'p-2',
|
|
186
172
|
})), onClick: () => setIsJson(true), children: "Open JSON Editor" }) }));
|
|
187
173
|
}
|
|
188
|
-
/**
|
|
189
|
-
* manipulate values without mutating the original object
|
|
190
|
-
*
|
|
191
|
-
* @returns a new manipulated object
|
|
192
|
-
*/
|
|
193
|
-
function manipulateValues(values, fieldName, update, clone = false) {
|
|
194
|
-
const root = clone ? { ...values } : values;
|
|
195
|
-
let current = root;
|
|
196
|
-
const segments = fieldName.split('.');
|
|
197
|
-
for (let i = 0; i < segments.length; i++) {
|
|
198
|
-
const segment = segments[i];
|
|
199
|
-
if (i !== segments.length - 1) {
|
|
200
|
-
let v = current[segment];
|
|
201
|
-
if (clone)
|
|
202
|
-
v = { ...v };
|
|
203
|
-
current[segment] = v;
|
|
204
|
-
current = v;
|
|
205
|
-
continue;
|
|
206
|
-
}
|
|
207
|
-
const updated = update(current[segment]);
|
|
208
|
-
if (updated === undefined) {
|
|
209
|
-
delete current[segment];
|
|
210
|
-
}
|
|
211
|
-
else {
|
|
212
|
-
current[segment] = updated;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
return root;
|
|
216
|
-
}
|
|
217
174
|
function useAuthInputs(securities) {
|
|
218
175
|
const inputs = useMemo(() => {
|
|
219
176
|
const result = [];
|
|
@@ -300,15 +257,30 @@ function useAuthInputs(securities) {
|
|
|
300
257
|
return result;
|
|
301
258
|
}, [securities]);
|
|
302
259
|
const mapInputs = (values) => {
|
|
260
|
+
const cloned = structuredClone(values);
|
|
303
261
|
for (const item of inputs) {
|
|
304
262
|
if (!item.mapOutput)
|
|
305
263
|
continue;
|
|
306
|
-
|
|
264
|
+
set(cloned, item.fieldName, item.mapOutput(get(values, item.fieldName)));
|
|
307
265
|
}
|
|
308
|
-
return
|
|
266
|
+
return cloned;
|
|
309
267
|
};
|
|
310
268
|
return { inputs, mapInputs };
|
|
311
269
|
}
|
|
270
|
+
function initAuthValues(values, inputs) {
|
|
271
|
+
for (const item of inputs) {
|
|
272
|
+
const stored = localStorage.getItem(AuthPrefix + item.original.id);
|
|
273
|
+
if (stored) {
|
|
274
|
+
const parsed = JSON.parse(stored);
|
|
275
|
+
if (typeof parsed === typeof item.defaultValue) {
|
|
276
|
+
set(values, item.fieldName, parsed);
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
set(values, item.fieldName, item.defaultValue);
|
|
281
|
+
}
|
|
282
|
+
return values;
|
|
283
|
+
}
|
|
312
284
|
function renderCustomField(fieldName, info, field, key) {
|
|
313
285
|
return (_jsx(Controller, {
|
|
314
286
|
// @ts-expect-error we use string here
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inputs.d.ts","sourceRoot":"","sources":["../../src/playground/inputs.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,SAAS,EAGf,MAAM,OAAO,CAAC;AAef,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAkDxD,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EAAE,MAAM,EACb,SAAS,EACT,GAAG,KAAK,EACT,EAAE;IACD,KAAK,EAAE,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IACvC,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,cAAc,CAAC,KAAK,CAAC,uDAwCxB;AAED,wBAAgB,SAAS,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,2CA8B7D;AA6FD,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,SAAS,EACT,UAAU,EACV,GAAG,KAAK,EACT,EAAE,cAAc,CAAC,WAAW,CAAC,GAAG;IAC/B,KAAK,EAAE,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IACvC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB,
|
|
1
|
+
{"version":3,"file":"inputs.d.ts","sourceRoot":"","sources":["../../src/playground/inputs.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,SAAS,EAGf,MAAM,OAAO,CAAC;AAef,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAkDxD,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EAAE,MAAM,EACb,SAAS,EACT,GAAG,KAAK,EACT,EAAE;IACD,KAAK,EAAE,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IACvC,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,cAAc,CAAC,KAAK,CAAC,uDAwCxB;AAED,wBAAgB,SAAS,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,2CA8B7D;AA6FD,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,SAAS,EACT,UAAU,EACV,GAAG,KAAK,EACT,EAAE,cAAc,CAAC,WAAW,CAAC,GAAG;IAC/B,KAAK,EAAE,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IACvC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB,uDAmGA;AAED,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EAAE,MAAM,EACb,SAAS,EACT,OAAO,EACP,IAAI,EACJ,UAAU,EACV,KAAS,EACT,QAAQ,EACR,WAAkB,EAClB,GAAG,KAAK,EACT,EAAE,cAAc,CAAC,WAAW,CAAC,GAAG;IAC/B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,aAAa,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,kDA4KA"}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { useMemo, useState, } from 'react';
|
|
4
|
-
import { ChevronDown, Plus, Trash2 } from '../icons.js';
|
|
5
|
-
import {
|
|
4
|
+
import { ChevronDown, Plus, Trash2, X } from '../icons.js';
|
|
5
|
+
import { set, useController, useFieldArray, useFormContext, } from 'react-hook-form';
|
|
6
6
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '../ui/components/select.js';
|
|
7
7
|
import { Input, labelVariants } from '../ui/components/input.js';
|
|
8
8
|
import { getDefaultValue } from './get-default-values.js';
|
|
9
9
|
import { cn } from 'fumadocs-ui/utils/cn';
|
|
10
10
|
import { buttonVariants } from 'fumadocs-ui/components/ui/button';
|
|
11
11
|
import { combineSchema } from '../utils/combine-schema.js';
|
|
12
|
-
import { schemaToString } from '../utils/schema-to-string.js';
|
|
12
|
+
import { FormatFlags, schemaToString } from '../utils/schema-to-string.js';
|
|
13
13
|
import { anyFields, useFieldInfo, useResolvedSchema, } from '../playground/schema.js';
|
|
14
14
|
function FieldLabel(props) {
|
|
15
15
|
return (_jsx("label", { ...props, className: cn('w-full inline-flex items-center gap-0.5', props.className), children: props.children }));
|
|
@@ -93,25 +93,32 @@ function DynamicProperties({ fieldName, filterKey = () => true, getType = () =>
|
|
|
93
93
|
} }), _jsx("button", { type: "button", className: cn(buttonVariants({ color: 'secondary', size: 'sm' }), 'px-4'), onClick: onAppend, children: "New" })] })] }));
|
|
94
94
|
}
|
|
95
95
|
export function FieldInput({ field, fieldName, isRequired, ...props }) {
|
|
96
|
-
const { control,
|
|
96
|
+
const { control, reset } = useFormContext();
|
|
97
|
+
const { field: { value, onChange, ...restField }, } = useController({
|
|
98
|
+
control,
|
|
99
|
+
name: fieldName,
|
|
100
|
+
});
|
|
97
101
|
if (field.type === 'string' && field.format === 'binary') {
|
|
98
|
-
return (
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
102
|
+
return (_jsxs("div", { ...props, children: [_jsx("label", { htmlFor: fieldName, className: cn(buttonVariants({
|
|
103
|
+
color: 'secondary',
|
|
104
|
+
className: 'w-full h-9 gap-2 truncate',
|
|
105
|
+
})), children: value instanceof File ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-fd-muted-foreground text-xs", children: "Selected" }), _jsx("span", { className: "truncate w-0 flex-1 text-end", children: value.name })] })) : (_jsx("span", { className: "text-fd-muted-foreground", children: "Upload" })) }), _jsx("input", { id: fieldName, type: "file", multiple: false, onChange: (e) => {
|
|
106
|
+
if (!e.target.files)
|
|
107
|
+
return;
|
|
108
|
+
onChange(e.target.files.item(0));
|
|
109
|
+
}, hidden: true, ...restField })] }));
|
|
106
110
|
}
|
|
107
111
|
if (field.type === 'boolean') {
|
|
108
|
-
return (
|
|
112
|
+
return (_jsxs(Select, { value: String(value), onValueChange: (value) => onChange(value === 'null' ? null : value === 'true'), disabled: restField.disabled, children: [_jsx(SelectTrigger, { id: fieldName, className: props.className, ...restField, children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "true", children: "True" }), _jsx(SelectItem, { value: "false", children: "False" }), !isRequired && _jsx(SelectItem, { value: "null", children: "Null" })] })] }));
|
|
109
113
|
}
|
|
110
114
|
if (field.type === 'null')
|
|
111
115
|
return;
|
|
112
|
-
return (_jsx(Input, { id: fieldName, placeholder: "Enter value", type: field.type === 'string' ? 'text' : 'number', step: field.type === 'number' ? 'any' : undefined, ...
|
|
113
|
-
|
|
114
|
-
|
|
116
|
+
return (_jsxs("div", { ...props, className: cn('flex flex-row gap-2', props.className), children: [_jsx(Input, { id: fieldName, placeholder: "Enter value", type: field.type === 'string' ? 'text' : 'number', step: field.type === 'number' ? 'any' : undefined, value: value ?? '', onChange: onChange, ...restField }), !isRequired && value !== undefined && (_jsx("button", { type: "button", onClick: () => {
|
|
117
|
+
reset((values) => {
|
|
118
|
+
set(values, fieldName, undefined);
|
|
119
|
+
return values;
|
|
120
|
+
});
|
|
121
|
+
}, className: "text-fd-muted-foreground", children: _jsx(X, { className: "size-4" }) }))] }));
|
|
115
122
|
}
|
|
116
123
|
export function FieldSet({ field: _field, fieldName, toolbar, name, isRequired, depth = 0, slotType, collapsible = true, ...props }) {
|
|
117
124
|
const field = useResolvedSchema(_field);
|
|
@@ -126,7 +133,7 @@ export function FieldSet({ field: _field, fieldName, toolbar, name, isRequired,
|
|
|
126
133
|
updateInfo({
|
|
127
134
|
oneOf: Number(e.target.value),
|
|
128
135
|
});
|
|
129
|
-
}, children: union.map((item, i) => (_jsx("option", { value: i, children: schemaToString(item) }, i))) })), toolbar] }) }));
|
|
136
|
+
}, children: union.map((item, i) => (_jsx("option", { value: i, children: schemaToString(item, undefined, FormatFlags.UseAlias) }, i))) })), toolbar] }) }));
|
|
130
137
|
}
|
|
131
138
|
if (Array.isArray(field.type)) {
|
|
132
139
|
const showSelect = field.type.length > 1;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/playground/schema.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAiB,SAAS,EAAiC,MAAM,OAAO,CAAC;AAMhF,UAAU,iBAAiB;IACzB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC1C,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACrC,GAAG,EAAE,OAAO,CAAC;CACd;AAED,KAAK,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AAE9C,MAAM,WAAW,SAAS;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AAGD,eAAO,MAAM,SAAS;;;;CAIG,CAAC;AAE1B,wBAAgB,cAAc,CAAC,EAC7B,UAAU,EACV,YAAY,EACZ,QAAQ,GACT,EAAE,IAAI,CAAC,iBAAiB,EAAE,KAAK,CAAC,GAAG;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,2CAsB1D;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,EACvC,KAAK,EAAE,MAAM,GACZ;IACD,IAAI,EAAE,SAAS,CAAC;IAChB,UAAU,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,KAAK,IAAI,CAAC;CACjD,
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/playground/schema.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAiB,SAAS,EAAiC,MAAM,OAAO,CAAC;AAMhF,UAAU,iBAAiB;IACzB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC1C,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACrC,GAAG,EAAE,OAAO,CAAC;CACd;AAED,KAAK,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AAE9C,MAAM,WAAW,SAAS;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AAGD,eAAO,MAAM,SAAS;;;;CAIG,CAAC;AAE1B,wBAAgB,cAAc,CAAC,EAC7B,UAAU,EACV,YAAY,EACZ,QAAQ,GACT,EAAE,IAAI,CAAC,iBAAiB,EAAE,KAAK,CAAC,GAAG;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,2CAsB1D;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,EACvC,KAAK,EAAE,MAAM,GACZ;IACD,IAAI,EAAE,SAAS,CAAC;IAChB,UAAU,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,KAAK,IAAI,CAAC;CACjD,CAqEA;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,CAQjC;AAED,wBAAgB,WAAW,CACzB,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,CAEjC"}
|
|
@@ -32,32 +32,10 @@ export function useFieldInfo(fieldName, schema, depth) {
|
|
|
32
32
|
const keyName = `${fieldName}:${depth}`;
|
|
33
33
|
const value = form.getValues(fieldName);
|
|
34
34
|
const [info, setInfo] = useState(() => {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
* We automatically merge `allOf` | `anyOf` if all members are objects, but it's also possible for them to behave same as a union (`oneOf`).
|
|
40
|
-
*/
|
|
41
|
-
function isUnion(anyOrAllOf) {
|
|
42
|
-
return anyOrAllOf.every((item) => {
|
|
43
|
-
if (typeof item === 'boolean')
|
|
44
|
-
return true;
|
|
45
|
-
const u = item.anyOf || item.allOf;
|
|
46
|
-
return item.type !== 'object' && (!u || isUnion(u));
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
function getUnion() {
|
|
50
|
-
if (schema.anyOf && isUnion(schema.anyOf)) {
|
|
51
|
-
return [schema.anyOf, 'anyOf'];
|
|
52
|
-
}
|
|
53
|
-
if (schema.allOf && isUnion(schema.allOf)) {
|
|
54
|
-
return [schema.allOf, 'allOf'];
|
|
55
|
-
}
|
|
56
|
-
if (schema.oneOf)
|
|
57
|
-
return [schema.oneOf, 'oneOf'];
|
|
58
|
-
}
|
|
59
|
-
function init() {
|
|
60
|
-
const union = getUnion();
|
|
35
|
+
const initialInfo = fieldInfoMap.get(keyName);
|
|
36
|
+
if (initialInfo)
|
|
37
|
+
return initialInfo;
|
|
38
|
+
const union = getUnion(schema);
|
|
61
39
|
if (union) {
|
|
62
40
|
const [members, field] = union;
|
|
63
41
|
let oneOf = members.findIndex((item) => ajv.validate(item, value));
|
|
@@ -81,7 +59,8 @@ export function useFieldInfo(fieldName, schema, depth) {
|
|
|
81
59
|
};
|
|
82
60
|
}
|
|
83
61
|
return { oneOf: -1 };
|
|
84
|
-
}
|
|
62
|
+
});
|
|
63
|
+
fieldInfoMap.set(keyName, info);
|
|
85
64
|
return {
|
|
86
65
|
info,
|
|
87
66
|
updateInfo: useEffectEvent((value) => {
|
|
@@ -120,3 +99,24 @@ export function useResolvedSchema(schema) {
|
|
|
120
99
|
export function fallbackAny(schema) {
|
|
121
100
|
return typeof schema === 'boolean' ? anyFields : schema;
|
|
122
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* We automatically merge `allOf` | `anyOf` if all members are objects, but it's also possible for them to behave same as a union (`oneOf`).
|
|
104
|
+
*/
|
|
105
|
+
function isUnion(anyOrAllOf) {
|
|
106
|
+
return anyOrAllOf.every((item) => {
|
|
107
|
+
if (typeof item === 'boolean')
|
|
108
|
+
return true;
|
|
109
|
+
const u = item.anyOf || item.allOf;
|
|
110
|
+
return item.type !== 'object' && (!u || isUnion(u));
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function getUnion(schema) {
|
|
114
|
+
if (schema.anyOf && isUnion(schema.anyOf)) {
|
|
115
|
+
return [schema.anyOf, 'anyOf'];
|
|
116
|
+
}
|
|
117
|
+
if (schema.allOf && isUnion(schema.allOf)) {
|
|
118
|
+
return [schema.allOf, 'allOf'];
|
|
119
|
+
}
|
|
120
|
+
if (schema.oneOf)
|
|
121
|
+
return [schema.oneOf, 'oneOf'];
|
|
122
|
+
}
|
|
@@ -4,7 +4,7 @@ import { createMethod } from '../../utils/schema.js';
|
|
|
4
4
|
import { idToTitle } from '../../utils/id-to-title.js';
|
|
5
5
|
import { Markdown } from '../markdown.js';
|
|
6
6
|
import { heading } from '../heading.js';
|
|
7
|
-
import { Schema } from '../schema.js';
|
|
7
|
+
import { Schema } from '../schema/index.js';
|
|
8
8
|
import { methodKeys } from '../../build-routes.js';
|
|
9
9
|
import { APIExample, APIExampleProvider, getAPIExamples, } from '../../render/operation/api-example.js';
|
|
10
10
|
import { MethodLabel } from '../../ui/components/method-label.js';
|
|
@@ -38,7 +38,7 @@ export function Operation({ type = 'operation', path, method, ctx, hasHead, head
|
|
|
38
38
|
if (!(type in ctx.mediaAdapters)) {
|
|
39
39
|
throw new Error(`Media type ${type} is not supported (in ${path})`);
|
|
40
40
|
}
|
|
41
|
-
return (_jsx(SelectTab, { value: type, children: _jsx(Schema, { name: "body", as: "body",
|
|
41
|
+
return (_jsx(SelectTab, { value: type, children: _jsx(Schema, { name: "body", as: "body", root: (content.schema ?? {}), required: body.required, readOnly: method.method === 'GET', writeOnly: method.method !== 'GET', ctx: ctx }) }, type));
|
|
42
42
|
})] }));
|
|
43
43
|
}
|
|
44
44
|
if (method.responses && ctx.showResponseSchema !== false) {
|
|
@@ -49,7 +49,7 @@ export function Operation({ type = 'operation', path, method, ctx, hasHead, head
|
|
|
49
49
|
const params = method.parameters?.filter((param) => param.in === type);
|
|
50
50
|
if (!params || params.length === 0)
|
|
51
51
|
return;
|
|
52
|
-
return (_jsxs(Fragment, { children: [heading(headingLevel, title, ctx), _jsx("div", { className: "flex flex-col", children: params.map((param) => (_jsx(Schema, { name: param.name,
|
|
52
|
+
return (_jsxs(Fragment, { children: [heading(headingLevel, title, ctx), _jsx("div", { className: "flex flex-col", children: params.map((param) => (_jsx(Schema, { name: param.name, root: {
|
|
53
53
|
...param.schema,
|
|
54
54
|
description: param.description ?? param.schema?.description,
|
|
55
55
|
deprecated: (param.deprecated ?? false) ||
|
|
@@ -83,10 +83,8 @@ export function Operation({ type = 'operation', path, method, ctx, hasHead, head
|
|
|
83
83
|
async function ResponseAccordion({ status, operation, ctx, }) {
|
|
84
84
|
const response = operation.responses[status];
|
|
85
85
|
const { generateTypeScriptSchema } = ctx;
|
|
86
|
-
const contentTypes = response.content
|
|
87
|
-
|
|
88
|
-
: null;
|
|
89
|
-
return (_jsxs(SelectTabs, { defaultValue: contentTypes?.[0][0], children: [_jsxs(AccordionHeader, { children: [_jsx(AccordionTrigger, { className: "font-mono", children: status }), contentTypes && (_jsx(SelectTabTrigger, { items: contentTypes.map((v) => v[0]) }))] }), _jsxs(AccordionContent, { className: "ps-4.5", children: [response.description && (_jsx("div", { className: "prose-no-margin", children: _jsx(Markdown, { text: response.description }) })), contentTypes?.map(async ([type, resType]) => {
|
|
86
|
+
const contentTypes = response.content ? Object.entries(response.content) : [];
|
|
87
|
+
return (_jsxs(SelectTabs, { defaultValue: contentTypes.at(0)?.[0], children: [_jsxs(AccordionHeader, { children: [_jsx(AccordionTrigger, { className: "font-mono", children: status }), contentTypes.length > 1 && (_jsx(SelectTabTrigger, { items: contentTypes.map((v) => v[0]) })), contentTypes.length === 1 && (_jsx("p", { className: "text-[13px] text-fd-muted-foreground", children: contentTypes[0][0] }))] }), _jsxs(AccordionContent, { className: "ps-4.5", children: [response.description && (_jsx("div", { className: "prose-no-margin", children: _jsx(Markdown, { text: response.description }) })), contentTypes?.map(async ([type, resType]) => {
|
|
90
88
|
const schema = resType.schema;
|
|
91
89
|
let ts;
|
|
92
90
|
if (generateTypeScriptSchema) {
|
|
@@ -95,7 +93,7 @@ async function ResponseAccordion({ status, operation, ctx, }) {
|
|
|
95
93
|
else if (generateTypeScriptSchema === undefined && schema) {
|
|
96
94
|
ts = await getTypescriptSchema(ctx.schema);
|
|
97
95
|
}
|
|
98
|
-
return (_jsxs(SelectTab, { value: type, className: "my-2", children: [ts && _jsx(CopyResponseTypeScript, { code: ts }), schema && (_jsx("div", { className: "border px-3 py-2 rounded-lg
|
|
96
|
+
return (_jsxs(SelectTab, { value: type, className: "my-2", children: [ts && _jsx(CopyResponseTypeScript, { code: ts }), schema && (_jsx("div", { className: "border px-3 py-2 rounded-lg", children: _jsx(Schema, { name: "response", root: schema, as: "body", readOnly: true, ctx: ctx }) }))] }, type));
|
|
99
97
|
})] })] }));
|
|
100
98
|
}
|
|
101
99
|
function WebhookCallback({ callback, ctx, headingLevel, }) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/render/renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAiBtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAiB,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAStE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IAEd,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/render/renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAiBtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAiB,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAStE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IAEd,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IAEb,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE;QACL,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,SAAS,CAAC;QACxB,KAAK,EAAE,MAAM,CAAC;KACf,EAAE,CAAC;CACL;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,aAAa,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IAC/B,GAAG,EAAE,aAAa,CAAC;QAAE,QAAQ,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IAC5C,OAAO,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IACrC,UAAU,EAAE,aAAa,CAAC;QAAE,QAAQ,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IAEnD,SAAS,EAAE,aAAa,CAAC,cAAc,CAAC,CAAC;IACzC,QAAQ,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;IACvC,mBAAmB,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IACjD,QAAQ,EAAE,aAAa,CAAC;QAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IAClE,OAAO,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IACrC,aAAa,EAAE,aAAa,CAAC;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IAC7E,YAAY,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAC;IAE/C;;OAEG;IACH,iBAAiB,EAAE,aAAa,CAAC,sBAAsB,CAAC,CAAC;IACzD,QAAQ,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;IACvC,aAAa,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAC;CAClD;AAED,wBAAgB,aAAa,IAAI,QAAQ,CA0DxC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import type { SchemaUIData } from '../../render/schema/server.js';
|
|
3
|
+
interface DataContextType extends SchemaUIData {
|
|
4
|
+
readOnly?: boolean;
|
|
5
|
+
writeOnly?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function SchemaUIProvider(props: {
|
|
8
|
+
value: DataContextType;
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export interface SchemaUIProps {
|
|
12
|
+
name: string;
|
|
13
|
+
required?: boolean;
|
|
14
|
+
as?: 'property' | 'body';
|
|
15
|
+
}
|
|
16
|
+
export declare function SchemaUI({ name, required, as, }: SchemaUIProps): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/render/schema/client.tsx"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,SAAS,EAOf,MAAM,OAAO,CAAC;AAOf,OAAO,KAAK,EAAc,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAUvE,UAAU,eAAgB,SAAQ,YAAY;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AA2BD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IACtC,KAAK,EAAE,eAAe,CAAC;IACvB,QAAQ,EAAE,SAAS,CAAC;CACrB,2CAEA;AAUD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,EAAE,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;CAC1B;AAED,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,QAAgB,EAChB,EAAe,GAChB,EAAE,aAAa,2CAiBf"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, Fragment, use, useCallback, useEffect, useMemo, useRef, useState, } from 'react';
|
|
4
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger, } from 'fumadocs-ui/components/tabs';
|
|
5
|
+
import { ObjectCollapsible, Property } from './ui.js';
|
|
6
|
+
import { Popover, PopoverContent, PopoverTrigger, } from 'fumadocs-ui/components/ui/popover';
|
|
7
|
+
import { cn } from 'fumadocs-ui/utils/cn';
|
|
8
|
+
import { cva } from 'class-variance-authority';
|
|
9
|
+
const typeVariants = cva('text-sm text-fd-muted-foreground font-mono', {
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
trigger: 'underline hover:text-fd-accent-foreground data-[state=open]:text-fd-accent-foreground',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
const PropertyContext = createContext({
|
|
17
|
+
renderRef: (props) => _jsx(RootRef, { ...props }),
|
|
18
|
+
});
|
|
19
|
+
const DataContext = createContext(null);
|
|
20
|
+
export function SchemaUIProvider(props) {
|
|
21
|
+
return _jsx(DataContext, { value: props.value, children: props.children });
|
|
22
|
+
}
|
|
23
|
+
function useData() {
|
|
24
|
+
return use(DataContext);
|
|
25
|
+
}
|
|
26
|
+
function useProperty() {
|
|
27
|
+
return use(PropertyContext);
|
|
28
|
+
}
|
|
29
|
+
export function SchemaUI({ name, required = false, as = 'property', }) {
|
|
30
|
+
const { $root, refs } = useData();
|
|
31
|
+
const schema = refs[$root];
|
|
32
|
+
if (as === 'property' || !isExpandable(schema)) {
|
|
33
|
+
return (_jsx(SchemaUIProperty, { name: name, "$type": $root, overrides: {
|
|
34
|
+
required,
|
|
35
|
+
} }));
|
|
36
|
+
}
|
|
37
|
+
return _jsx(SchemaUIContent, { "$type": $root });
|
|
38
|
+
}
|
|
39
|
+
function SchemaUIContent({ $type }) {
|
|
40
|
+
const { refs, readOnly, writeOnly } = useData();
|
|
41
|
+
const schema = refs[$type];
|
|
42
|
+
if ((schema.readOnly && !readOnly) || (schema.writeOnly && !writeOnly))
|
|
43
|
+
return;
|
|
44
|
+
let child = _jsx(_Fragment, {});
|
|
45
|
+
if (schema.type === 'or' && schema.items.length > 0) {
|
|
46
|
+
child = (_jsxs(_Fragment, { children: [child, _jsxs(Tabs, { defaultValue: schema.items[0].$type, children: [_jsx(TabsList, { children: schema.items.map((item) => (_jsx(TabsTrigger, { value: item.$type, children: item.name }, item.$type))) }), schema.items.map((item) => (_jsx(TabsContent, { value: item.$type, forceMount: undefined, className: "py-0", children: _jsx(SchemaUIContent, { ...item }) }, item.$type)))] })] }));
|
|
47
|
+
}
|
|
48
|
+
if (schema.type === 'object' && schema.props.length > 0) {
|
|
49
|
+
child = (_jsxs(_Fragment, { children: [child, schema.props.map((prop) => (_jsx(SchemaUIProperty, { name: prop.name, "$type": prop.$type, overrides: { required: prop.required } }, prop.name)))] }));
|
|
50
|
+
}
|
|
51
|
+
if (schema.type === 'array') {
|
|
52
|
+
child = (_jsxs(_Fragment, { children: [child, _jsx(ObjectCollapsible, { name: "Array item", children: _jsx(SchemaUIContent, { "$type": schema.item.$type }) })] }));
|
|
53
|
+
}
|
|
54
|
+
return child;
|
|
55
|
+
}
|
|
56
|
+
function SchemaUIProperty({ name, $type, overrides, }) {
|
|
57
|
+
const { renderRef } = useProperty();
|
|
58
|
+
const { refs, readOnly, writeOnly } = useData();
|
|
59
|
+
const schema = refs[$type];
|
|
60
|
+
if ((schema.readOnly && !readOnly) || (schema.writeOnly && !writeOnly))
|
|
61
|
+
return;
|
|
62
|
+
let type = schema.typeName;
|
|
63
|
+
if (schema.type === 'or' && schema.items.length > 0) {
|
|
64
|
+
type = (_jsx("span", { className: cn(typeVariants(), 'flex flex-row gap-2 items-center'), children: schema.items.map((item, i) => (_jsxs(Fragment, { children: [i > 0 && _jsx("span", { children: "|" }), renderRef({
|
|
65
|
+
pathName: name,
|
|
66
|
+
text: item.name,
|
|
67
|
+
$ref: item.$type,
|
|
68
|
+
})] }, item.$type))) }));
|
|
69
|
+
}
|
|
70
|
+
if (schema.type === 'object' && schema.props.length > 0) {
|
|
71
|
+
type = renderRef({
|
|
72
|
+
text: schema.aliasName,
|
|
73
|
+
pathName: name,
|
|
74
|
+
$ref: $type,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
if (schema.type === 'array') {
|
|
78
|
+
type = renderRef({
|
|
79
|
+
text: schema.aliasName,
|
|
80
|
+
pathName: _jsxs(_Fragment, { children: [name, "[]"] }),
|
|
81
|
+
$ref: schema.item.$type,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return (_jsxs(Property, { name: name, type: type, deprecated: schema.deprecated, ...overrides, children: [schema.description, schema.infoTags && schema.infoTags.length > 0 && (_jsx("div", { className: "flex flex-row gap-2 flex-wrap my-2 not-prose empty:hidden", children: schema.infoTags.map((tag, i) => (_jsx(Fragment, { children: tag }, i))) }))] }));
|
|
85
|
+
}
|
|
86
|
+
function SchemaUIPopover({ initialPath, }) {
|
|
87
|
+
const [path, setPath] = useState(initialPath);
|
|
88
|
+
const ref = useRef(null);
|
|
89
|
+
const last = path.findLast((item) => item.$ref !== undefined);
|
|
90
|
+
useEffect(() => {
|
|
91
|
+
const element = ref.current;
|
|
92
|
+
if (!element || !element.parentElement)
|
|
93
|
+
return;
|
|
94
|
+
// reset scroll
|
|
95
|
+
element.parentElement.scrollTop = 0;
|
|
96
|
+
}, [last?.$ref]);
|
|
97
|
+
const context = useMemo(() => ({
|
|
98
|
+
renderRef: (props) => (_jsx(LinkRef, { ...props, onInsert: (name, $ref) => {
|
|
99
|
+
setPath((path) => [...path, { name, $ref }]);
|
|
100
|
+
} })),
|
|
101
|
+
}), []);
|
|
102
|
+
if (!last)
|
|
103
|
+
return;
|
|
104
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { className: "sticky top-0 flex flex-row flex-wrap items-center text-sm font-medium font-mono bg-fd-muted p-2", children: path.map((item, i) => {
|
|
105
|
+
const isDuplicated = path.some((other, j) => j < i && other.$ref === item.$ref);
|
|
106
|
+
const className = cn(isDuplicated && 'text-orange-400', item.$ref && 'hover:underline hover:text-fd-accent-foreground');
|
|
107
|
+
const node = item.$ref ? (_jsx("button", { onClick: () => setPath((path) => path.slice(0, i + 1)), className: className, children: item.name })) : (_jsx("span", { className: className, children: item.name }));
|
|
108
|
+
return (_jsxs(Fragment, { children: [i > 0 && '.', node] }, i));
|
|
109
|
+
}) }), _jsx(PropertyContext, { value: context, children: _jsx("div", { ref: ref, className: "px-2", children: _jsx(SchemaUIContent, { "$type": last.$ref }) }) })] }));
|
|
110
|
+
}
|
|
111
|
+
function RootRef({ text, $ref, pathName }) {
|
|
112
|
+
const { refs } = useData();
|
|
113
|
+
const ref = useCallback((element) => {
|
|
114
|
+
if (!element || element.style.getPropertyValue('--initial-height'))
|
|
115
|
+
return;
|
|
116
|
+
element.style.setProperty('--initial-height', `${element.clientHeight}px`);
|
|
117
|
+
}, []);
|
|
118
|
+
if (!isExpandable(refs[$ref])) {
|
|
119
|
+
return _jsx("span", { className: cn(typeVariants()), children: text });
|
|
120
|
+
}
|
|
121
|
+
return (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { className: cn(typeVariants({ variant: 'trigger' })), children: text }), _jsx(PopoverContent, { ref: ref, className: "w-[600px] min-h-(--initial-height,0) max-h-[460px] p-0", children: _jsx(SchemaUIPopover, { initialPath: [
|
|
122
|
+
{
|
|
123
|
+
name: pathName,
|
|
124
|
+
$ref: $ref,
|
|
125
|
+
},
|
|
126
|
+
] }) })] }));
|
|
127
|
+
}
|
|
128
|
+
function LinkRef({ $ref, pathName, onInsert, text, }) {
|
|
129
|
+
const { refs } = useData();
|
|
130
|
+
if (!isExpandable(refs[$ref])) {
|
|
131
|
+
return _jsx("span", { className: cn(typeVariants()), children: text });
|
|
132
|
+
}
|
|
133
|
+
return (_jsx("button", { className: cn(typeVariants({ variant: 'trigger' })), onClick: () => {
|
|
134
|
+
onInsert(pathName, $ref);
|
|
135
|
+
}, children: text }));
|
|
136
|
+
}
|
|
137
|
+
function isExpandable(schema) {
|
|
138
|
+
return schema.type !== 'primitive';
|
|
139
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type SchemaUIOptions } from '../../render/schema/server.js';
|
|
2
|
+
import { type SchemaUIProps } from '../../render/schema/client.js';
|
|
3
|
+
export declare function Schema(props: SchemaUIOptions & SchemaUIProps & {
|
|
4
|
+
readOnly?: boolean;
|
|
5
|
+
writeOnly?: boolean;
|
|
6
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/render/schema/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,EAEL,KAAK,aAAa,EAEnB,MAAM,wBAAwB,CAAC;AAEhC,wBAAgB,MAAM,CACpB,KAAK,EAAE,eAAe,GACpB,aAAa,GAAG;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,2CAeJ"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { generateSchemaUI } from '../../render/schema/server.js';
|
|
3
|
+
import { SchemaUI, SchemaUIProvider, } from '../../render/schema/client.js';
|
|
4
|
+
export function Schema(props) {
|
|
5
|
+
const data = generateSchemaUI(props);
|
|
6
|
+
return (_jsx(SchemaUIProvider, { value: {
|
|
7
|
+
...data,
|
|
8
|
+
readOnly: props.readOnly,
|
|
9
|
+
writeOnly: props.writeOnly,
|
|
10
|
+
}, children: _jsx(SchemaUI, { name: props.name, required: props.required, as: props.as }) }));
|
|
11
|
+
}
|