fumadocs-openapi 9.5.1 → 9.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/playground/client.d.ts.map +1 -1
  2. package/dist/playground/client.js +36 -64
  3. package/dist/playground/inputs.d.ts.map +1 -1
  4. package/dist/playground/inputs.js +24 -17
  5. package/dist/playground/schema.d.ts.map +1 -1
  6. package/dist/playground/schema.js +27 -27
  7. package/dist/render/operation/index.js +6 -8
  8. package/dist/render/renderer.d.ts +1 -1
  9. package/dist/render/renderer.d.ts.map +1 -1
  10. package/dist/render/schema/client.d.ts +18 -0
  11. package/dist/render/schema/client.d.ts.map +1 -0
  12. package/dist/render/schema/client.js +139 -0
  13. package/dist/render/schema/index.d.ts +7 -0
  14. package/dist/render/schema/index.d.ts.map +1 -0
  15. package/dist/render/schema/index.js +11 -0
  16. package/dist/render/schema/server.d.ts +43 -0
  17. package/dist/render/schema/server.d.ts.map +1 -0
  18. package/dist/render/schema/server.js +206 -0
  19. package/dist/render/schema/ui.d.ts +16 -0
  20. package/dist/render/schema/ui.d.ts.map +1 -0
  21. package/dist/render/schema/ui.js +14 -0
  22. package/dist/server/create.d.ts +11 -0
  23. package/dist/server/create.d.ts.map +1 -1
  24. package/dist/ui/components/method-label.d.ts +1 -1
  25. package/dist/ui/contexts/code-example.d.ts +4 -1
  26. package/dist/ui/contexts/code-example.d.ts.map +1 -1
  27. package/dist/ui/contexts/code-example.js +1 -1
  28. package/dist/ui/index.d.ts +3 -7
  29. package/dist/ui/index.d.ts.map +1 -1
  30. package/dist/ui/index.js +2 -13
  31. package/dist/utils/schema-to-string.d.ts +5 -1
  32. package/dist/utils/schema-to-string.d.ts.map +1 -1
  33. package/dist/utils/schema-to-string.js +25 -24
  34. package/package.json +11 -11
  35. package/dist/render/schema.d.ts +0 -13
  36. package/dist/render/schema.d.ts.map +0 -1
  37. 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;AAQzB,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;AAwBzE,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,2CAyLb"}
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
- function initAuthValues(values, inputs) {
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
- values = manipulateValues(values, item.fieldName, item.mapOutput, true);
264
+ set(cloned, item.fieldName, item.mapOutput(get(values, item.fieldName)));
307
265
  }
308
- return values;
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,uDA8FA;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
+ {"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 { Controller, useController, useFieldArray, useFormContext, } from 'react-hook-form';
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, register } = useFormContext();
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 (_jsx(Controller, { control: control, name: fieldName, render: ({ field: { value, onChange, ...restField } }) => (_jsxs("div", { ...props, children: [_jsx("label", { htmlFor: fieldName, className: cn(buttonVariants({
99
- color: 'secondary',
100
- className: 'w-full h-9 gap-2 truncate',
101
- })), 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) => {
102
- if (!e.target.files)
103
- return;
104
- onChange(e.target.files.item(0));
105
- }, hidden: true, ...restField })] })) }));
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 (_jsx(Controller, { control: control, name: fieldName, render: ({ field: { value, onChange, ...restField } }) => (_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" })] })] })) }));
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, ...register(fieldName, {
113
- valueAsNumber: field.type === 'number' || field.type === 'integer',
114
- }), ...props }));
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,CA8FA;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"}
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
- return fieldInfoMap.get(keyName) ?? init();
36
- });
37
- fieldInfoMap.set(keyName, info);
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", schema: (content.schema ?? {}), required: body.required, readOnly: method.method === 'GET', writeOnly: method.method !== 'GET', ctx: ctx }) }, type));
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, schema: {
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
- ? Object.entries(response.content)
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 overflow-auto max-h-[400px]", children: _jsx(Schema, { name: "response", schema: schema, as: "body", readOnly: true, ctx: ctx }) }))] }, type));
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, }) {
@@ -17,7 +17,7 @@ export interface APIInfoProps {
17
17
  }
18
18
  export interface PropertyProps {
19
19
  name: string;
20
- type: string;
20
+ type: ReactNode;
21
21
  required?: boolean;
22
22
  deprecated?: boolean;
23
23
  children?: ReactNode;
@@ -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,MAAM,CAAC;IACb,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"}
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
+ }