fumadocs-openapi 11.4.3 → 12.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/css/generated/shared.css +1 -1
  2. package/css/preset.css +0 -1
  3. package/dist/_virtual/_rolldown/runtime.js +10 -1
  4. package/dist/generate-file.d.ts +2 -2
  5. package/dist/generate-file.js +1 -1
  6. package/dist/i18n.d.ts +6 -8
  7. package/dist/i18n.js +2 -17
  8. package/dist/index.browser.d.ts +13 -0
  9. package/dist/index.browser.js +11 -0
  10. package/dist/index.d.ts +5 -2
  11. package/dist/index.js +3 -1
  12. package/dist/operation.d.ts +133 -0
  13. package/dist/operation.js +296 -0
  14. package/dist/packages/shared-api/dist/.translations/index.d.ts +29 -0
  15. package/dist/packages/shared-api/dist/.translations/keys.js +28 -0
  16. package/dist/packages/shared-api/dist/auto-anchor/client.js +20 -0
  17. package/dist/packages/shared-api/dist/auto-anchor/index.js +17 -0
  18. package/dist/packages/shared-api/dist/codegen.d.ts +42 -0
  19. package/dist/packages/shared-api/dist/codegen.js +35 -0
  20. package/dist/packages/shared-api/dist/components/accordion.js +71 -0
  21. package/dist/packages/shared-api/dist/components/badge.js +21 -0
  22. package/dist/packages/shared-api/dist/components/collapsible.d.ts +7 -0
  23. package/dist/packages/shared-api/dist/components/collapsible.js +16 -0
  24. package/dist/packages/shared-api/dist/components/defaults.d.ts +20 -0
  25. package/dist/packages/shared-api/dist/components/defaults.js +70 -0
  26. package/dist/packages/shared-api/dist/components/dialog.js +55 -0
  27. package/dist/packages/shared-api/dist/components/input.js +14 -0
  28. package/dist/packages/shared-api/dist/components/label.js +11 -0
  29. package/dist/packages/shared-api/dist/components/playground/inputs.js +439 -0
  30. package/dist/packages/shared-api/dist/components/playground/schema.js +112 -0
  31. package/dist/packages/shared-api/dist/components/popover.js +23 -0
  32. package/dist/packages/shared-api/dist/components/schema/client.d.ts +12 -0
  33. package/dist/packages/shared-api/dist/components/schema/client.js +508 -0
  34. package/dist/packages/shared-api/dist/components/schema/index.d.ts +9 -0
  35. package/dist/packages/shared-api/dist/components/schema/index.js +28 -0
  36. package/dist/packages/shared-api/dist/components/select-tab.js +54 -0
  37. package/dist/packages/shared-api/dist/components/select.js +70 -0
  38. package/dist/packages/shared-api/dist/components/spinner.js +14 -0
  39. package/dist/packages/shared-api/dist/i18n.d.ts +3 -0
  40. package/dist/packages/shared-api/dist/i18n.js +7 -0
  41. package/dist/packages/shared-api/dist/utils/cn.js +2 -0
  42. package/dist/packages/shared-api/dist/utils/id-to-title.js +12 -0
  43. package/dist/packages/shared-api/dist/utils/is-plain-object.js +8 -0
  44. package/dist/packages/shared-api/dist/utils/merge-refs.js +11 -0
  45. package/dist/packages/shared-api/dist/utils/url.js +13 -0
  46. package/dist/{utils → packages/shared-api/dist/utils}/use-query.js +2 -1
  47. package/dist/packages/shared-api/dist/utils/use-server-store.js +56 -0
  48. package/dist/playground/auth.d.ts +37 -0
  49. package/dist/playground/auth.js +216 -21
  50. package/dist/playground/fetcher.d.ts +11 -1
  51. package/dist/playground/index.d.ts +3 -0
  52. package/dist/playground/index.js +3 -0
  53. package/dist/requests/generators/index.d.ts +4 -4
  54. package/dist/requests/generators/index.js +2 -2
  55. package/dist/requests/index.d.ts +4 -0
  56. package/dist/requests/index.js +3 -0
  57. package/dist/requests/media/adapter.d.ts +1 -0
  58. package/dist/requests/media/encode.d.ts +7 -2
  59. package/dist/requests/media/resolve-adapter.d.ts +20 -0
  60. package/dist/server/index.d.ts +4 -7
  61. package/dist/server/index.js +1 -7
  62. package/dist/types.d.ts +0 -14
  63. package/dist/ui/base.d.ts +3 -2
  64. package/dist/ui/base.js +15 -166
  65. package/dist/ui/components/codeblock.js +3 -10
  66. package/dist/ui/components/heading.js +10 -19
  67. package/dist/ui/components/markdown.js +4 -6
  68. package/dist/ui/components/method-label.js +2 -17
  69. package/dist/ui/components/schema.js +28 -0
  70. package/dist/ui/index.d.ts +7 -198
  71. package/dist/ui/index.js +1 -3
  72. package/dist/ui/operation/index.js +142 -229
  73. package/dist/ui/operation/request-tabs.js +15 -23
  74. package/dist/ui/operation/response-tabs.js +9 -53
  75. package/dist/ui/operation/usage-tabs.js +35 -93
  76. package/dist/{playground → ui/playground}/client.d.ts +10 -21
  77. package/dist/ui/playground/client.js +432 -0
  78. package/dist/{playground → ui/playground}/components/oauth-dialog.js +26 -91
  79. package/dist/{playground → ui/playground}/components/result-display.d.ts +2 -2
  80. package/dist/{playground → ui/playground}/components/result-display.js +7 -7
  81. package/dist/{playground → ui/playground}/components/server-select.js +12 -13
  82. package/dist/{playground → ui/playground}/status-info.js +2 -2
  83. package/dist/{scalar → ui/scalar}/client.js +7 -5
  84. package/dist/{scalar → ui/scalar}/index.d.ts +2 -2
  85. package/dist/{scalar → ui/scalar}/index.js +3 -7
  86. package/dist/utils/create-page.d.ts +216 -0
  87. package/dist/utils/create-page.js +221 -0
  88. package/dist/utils/document/dereference.d.ts +2 -2
  89. package/dist/utils/document/dereference.js +8 -3
  90. package/dist/utils/document/load.js +2 -2
  91. package/dist/utils/get-example-requests.js +11 -13
  92. package/dist/utils/pages/builder.d.ts +15 -2
  93. package/dist/utils/pages/builder.js +6 -6
  94. package/dist/utils/pages/preset-auto.d.ts +1 -1
  95. package/dist/utils/pages/preset-auto.js +3 -3
  96. package/dist/utils/pages/to-static-data.js +4 -4
  97. package/dist/utils/pages/to-text.d.ts +1 -1
  98. package/dist/utils/pages/to-text.js +3 -5
  99. package/dist/utils/schema.js +5 -5
  100. package/dist/utils/use-server.d.ts +24 -0
  101. package/dist/utils/use-server.js +57 -0
  102. package/package.json +28 -20
  103. package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/2.0-to-3.0/upgrade-from-two-to-three.js +0 -508
  104. package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/3.0-to-3.1/upgrade-from-three-to-three-one.js +0 -152
  105. package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/3.1-to-3.2/upgrade-from-three-one-to-three-two.js +0 -61
  106. package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/helpers/traverse.js +0 -25
  107. package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/upgrade.js +0 -15
  108. package/dist/playground/client.js +0 -574
  109. package/dist/ui/contexts/api.d.ts +0 -17
  110. package/dist/ui/contexts/api.js +0 -84
  111. package/dist/ui/create-client.d.ts +0 -9
  112. package/dist/ui/create-client.js +0 -7
  113. package/dist/ui/operation/context.d.ts +0 -15
  114. package/dist/ui/operation/context.js +0 -48
  115. package/dist/ui/operation/request-tabs.d.ts +0 -12
  116. package/dist/ui/operation/response-tabs.d.ts +0 -30
  117. package/dist/utils/get-example-requests.d.ts +0 -11
  118. package/dist/utils/schema.d.ts +0 -3
  119. package/dist/utils/storage-key.js +0 -15
@@ -0,0 +1,439 @@
1
+ "use client";
2
+ import { cn } from "../../utils/cn.js";
3
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../select.js";
4
+ import { anyFields, useFieldInfo, useResolvedSchema, useSchemaContext, useSchemaUtils } from "./schema.js";
5
+ import { Input } from "../input.js";
6
+ import { useState } from "react";
7
+ import { stringify } from "@fumadocs/json-schema";
8
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
9
+ import { useArray, useDataEngine, useFieldValue, useObject } from "@fumari/stf";
10
+ import { stringifyFieldKey } from "@fumari/stf/lib/utils";
11
+ import { useTranslations } from "@fuma-translate/react";
12
+ import { ChevronRight, Plus, Trash2, X } from "lucide-react";
13
+ import { cva } from "class-variance-authority";
14
+ import { buttonVariants } from "fumadocs-ui/components/ui/button";
15
+ //#region ../shared-api/dist/components/playground/inputs.js
16
+ const fieldLabelVariants = cva("w-full inline-flex items-center gap-0.5");
17
+ function FieldLabelType(props) {
18
+ return /* @__PURE__ */ jsx("code", {
19
+ ...props,
20
+ className: cn("text-xs text-fd-muted-foreground", props.className),
21
+ children: props.children
22
+ });
23
+ }
24
+ const labelClassName = "text-xs font-medium text-fd-foreground peer-disabled:cursor-not-allowed peer-disabled:opacity-70";
25
+ function ObjectInput({ field: _field, fieldName, ...props }) {
26
+ const { generateDefault } = useSchemaUtils();
27
+ const field = useResolvedSchema(_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;
31
+ const [nextName, setNextName] = useState("");
32
+ const { properties, onAppend, onDelete, _objectKeys } = useObject(fieldName, {
33
+ lazy: isLazy,
34
+ defaultValue: () => generateDefault(field),
35
+ properties: field.properties ?? {},
36
+ fallback: additionalProperties,
37
+ patternProperties
38
+ });
39
+ const hiddenProperties = isLazy ? schemaPropKeys.filter((key) => !_objectKeys.includes(key)) : [];
40
+ const t = useTranslations({ note: "playground" });
41
+ return /* @__PURE__ */ jsxs("div", {
42
+ ...props,
43
+ className: cn("grid grid-cols-1 gap-4 @md:grid-cols-2 *:data-[collapsible=true]:order-last", props.className),
44
+ children: [
45
+ isLazy && hiddenProperties.length > 0 && /* @__PURE__ */ jsxs(Select, {
46
+ value: "",
47
+ onValueChange: (v) => v !== null && onAppend(v),
48
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
49
+ className: "col-span-full",
50
+ children: /* @__PURE__ */ jsx(SelectValue, { placeholder: t("Show Property") })
51
+ }), /* @__PURE__ */ jsx(SelectContent, { children: hiddenProperties.map((key) => /* @__PURE__ */ jsx(SelectItem, {
52
+ value: key,
53
+ children: key
54
+ }, key)) })]
55
+ }),
56
+ properties.map((child) => {
57
+ let toolbar = null;
58
+ if (child.kind === "pattern" || child.kind === "fallback") toolbar = /* @__PURE__ */ jsx("button", {
59
+ type: "button",
60
+ "aria-label": t("Remove Item", { note: "aria-label" }),
61
+ className: cn(buttonVariants({
62
+ variant: "outline",
63
+ size: "icon-xs"
64
+ })),
65
+ onClick: () => {
66
+ onDelete(child.key);
67
+ },
68
+ children: /* @__PURE__ */ jsx(Trash2, {})
69
+ });
70
+ return /* @__PURE__ */ jsx(FieldSet, {
71
+ name: child.key,
72
+ field: child.info,
73
+ fieldName: child.field,
74
+ isRequired: field.required?.includes(child.key),
75
+ toolbar
76
+ }, child.key);
77
+ }),
78
+ isDynamic && /* @__PURE__ */ jsxs("div", {
79
+ className: "flex gap-2 order-last col-span-full",
80
+ children: [/* @__PURE__ */ jsx(Input, {
81
+ value: nextName,
82
+ placeholder: t("Enter Property Name"),
83
+ onChange: (e) => setNextName(e.target.value),
84
+ onKeyDown: (e) => {
85
+ if (e.key === "Enter") {
86
+ setNextName("");
87
+ onAppend(nextName);
88
+ e.preventDefault();
89
+ }
90
+ }
91
+ }), /* @__PURE__ */ jsx("button", {
92
+ type: "button",
93
+ className: cn(buttonVariants({
94
+ variant: "secondary",
95
+ size: "sm"
96
+ }), "px-4"),
97
+ onClick: () => {
98
+ onAppend(nextName);
99
+ setNextName("");
100
+ },
101
+ children: t("New")
102
+ })]
103
+ })
104
+ ]
105
+ });
106
+ }
107
+ function JsonInput({ fieldName }) {
108
+ const engine = useDataEngine();
109
+ const [error, setError] = useState(null);
110
+ const [value, setValue] = useState(() => JSON.stringify(engine.init(fieldName, {}), null, 2));
111
+ return /* @__PURE__ */ jsxs("div", {
112
+ className: "flex flex-col bg-fd-secondary text-fd-secondary-foreground overflow-hidden border rounded-lg",
113
+ children: [/* @__PURE__ */ jsx("textarea", {
114
+ value,
115
+ className: "p-2 h-[240px] text-sm font-mono resize-none focus-visible:outline-none",
116
+ onChange: (v) => {
117
+ setValue(v.target.value);
118
+ try {
119
+ engine.update(fieldName, JSON.parse(v.target.value));
120
+ setError(null);
121
+ } catch (e) {
122
+ if (e instanceof Error) setError(e.message);
123
+ }
124
+ }
125
+ }), /* @__PURE__ */ jsx("p", {
126
+ className: "p-2 text-xs font-mono border-t text-red-400 empty:hidden",
127
+ children: error
128
+ })]
129
+ });
130
+ }
131
+ function FieldInput({ field, fieldName, isRequired, ...props }) {
132
+ const [value, setValue] = useFieldValue(fieldName);
133
+ const id = stringifyFieldKey(fieldName);
134
+ const t = useTranslations({ note: "playground" });
135
+ if (field.type === "null") return;
136
+ if (field.type === "string" && field.format === "binary") return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("label", {
137
+ htmlFor: id,
138
+ className: cn(buttonVariants({
139
+ variant: "secondary",
140
+ className: "w-full h-9 gap-2 truncate"
141
+ })),
142
+ children: value instanceof File ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
143
+ className: "text-fd-muted-foreground text-xs",
144
+ children: t("Selected")
145
+ }), /* @__PURE__ */ jsx("span", {
146
+ className: "truncate w-0 flex-1 text-end",
147
+ children: value.name
148
+ })] }) : /* @__PURE__ */ jsx("span", {
149
+ className: "text-fd-muted-foreground",
150
+ children: t("Upload")
151
+ })
152
+ }), /* @__PURE__ */ jsx("input", {
153
+ id,
154
+ type: "file",
155
+ multiple: false,
156
+ onChange: (e) => {
157
+ if (!e.target.files || e.target.files.length === 0) return;
158
+ setValue(e.target.files.item(0));
159
+ },
160
+ hidden: true
161
+ })] });
162
+ if (field.enum && field.enum.length > 0) {
163
+ const idx = field.enum.indexOf(value);
164
+ const items = [...field.enum.map((item, i) => ({
165
+ value: String(i),
166
+ label: typeof item === "string" ? item : JSON.stringify(item, null, 2)
167
+ })), ...!isRequired ? [{
168
+ value: "-1",
169
+ label: /* @__PURE__ */ jsx("span", {
170
+ className: "text-fd-muted-foreground",
171
+ children: t("Unset")
172
+ })
173
+ }] : []];
174
+ return /* @__PURE__ */ jsxs(Select, {
175
+ items,
176
+ value: idx === -1 && isRequired ? "" : String(idx),
177
+ onValueChange: (v) => setValue(field.enum[Number(v)]),
178
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
179
+ id,
180
+ ...props,
181
+ children: /* @__PURE__ */ jsx(SelectValue, { placeholder: t("Select") })
182
+ }), /* @__PURE__ */ jsx(SelectContent, { children: items.map((item) => /* @__PURE__ */ jsx(SelectItem, {
183
+ value: item.value,
184
+ children: item.label
185
+ }, item.value)) })]
186
+ });
187
+ }
188
+ if (field.type === "boolean") {
189
+ const items = [
190
+ {
191
+ value: "true",
192
+ label: "True"
193
+ },
194
+ {
195
+ value: "false",
196
+ label: "False"
197
+ },
198
+ ...!isRequired ? [{
199
+ value: "undefined",
200
+ label: /* @__PURE__ */ jsx("span", {
201
+ className: "text-fd-muted-foreground",
202
+ children: t("Unset")
203
+ })
204
+ }] : []
205
+ ];
206
+ return /* @__PURE__ */ jsxs(Select, {
207
+ items,
208
+ value: value === void 0 && isRequired ? "" : String(value),
209
+ onValueChange: (value) => setValue(value === "undefined" ? void 0 : value === "true"),
210
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
211
+ id,
212
+ ...props,
213
+ children: /* @__PURE__ */ jsx(SelectValue, {})
214
+ }), /* @__PURE__ */ jsx(SelectContent, { children: items.map((item) => /* @__PURE__ */ jsx(SelectItem, {
215
+ value: item.value,
216
+ children: item.label
217
+ }, item.value)) })]
218
+ });
219
+ }
220
+ const isNumber = field.type === "integer" || field.type === "number";
221
+ return /* @__PURE__ */ jsx(Input, {
222
+ id,
223
+ placeholder: t("Enter value"),
224
+ type: isNumber ? "number" : "text",
225
+ step: field.type === "integer" ? 1 : void 0,
226
+ value: String(value ?? ""),
227
+ onChange: (e) => {
228
+ if (isNumber) setValue(Number.isNaN(e.target.valueAsNumber) ? void 0 : e.target.valueAsNumber);
229
+ else if (!isNumber) setValue(e.target.value);
230
+ }
231
+ });
232
+ }
233
+ function FieldSet({ field: _field, fieldName, toolbar, name, isRequired, depth = 0, slotType, collapsible = true, ...props }) {
234
+ const { readOnly, writeOnly } = useSchemaContext();
235
+ const { generateDefault } = useSchemaUtils();
236
+ const field = useResolvedSchema(_field);
237
+ const [show, setShow] = useState(!collapsible);
238
+ const { info, updateInfo } = useFieldInfo(fieldName, field, depth);
239
+ const id = stringifyFieldKey(fieldName);
240
+ const dataEngine = useDataEngine();
241
+ const [isDefined] = useFieldValue(fieldName, { compute(currentValue) {
242
+ return currentValue !== void 0;
243
+ } });
244
+ if (_field === false) return;
245
+ if (field.readOnly && !readOnly) return;
246
+ if (field.writeOnly && !writeOnly) return;
247
+ if (collapsible && !isDefined && show) setShow(false);
248
+ function renderLabelTrigger(schema = field) {
249
+ if (!collapsible) return renderLabelName();
250
+ return /* @__PURE__ */ jsxs("button", {
251
+ type: "button",
252
+ className: cn(labelClassName, "inline-flex items-center gap-1 font-mono me-auto"),
253
+ onClick: () => {
254
+ dataEngine.init(fieldName, generateDefault(schema));
255
+ setShow((prev) => !prev);
256
+ },
257
+ children: [
258
+ /* @__PURE__ */ jsx(ChevronRight, { className: cn("size-3.5 text-fd-muted-foreground", show && "rotate-90") }),
259
+ name,
260
+ isRequired && /* @__PURE__ */ jsx("span", {
261
+ className: "text-red-400/80",
262
+ children: "*"
263
+ })
264
+ ]
265
+ });
266
+ }
267
+ function renderLabelName() {
268
+ return /* @__PURE__ */ jsxs("span", {
269
+ className: cn(labelClassName, "font-mono me-auto"),
270
+ children: [name, isRequired && /* @__PURE__ */ jsx("span", {
271
+ className: "text-red-400/80 mx-1",
272
+ children: "*"
273
+ })]
274
+ });
275
+ }
276
+ function renderUnsetButton() {
277
+ return /* @__PURE__ */ jsx("button", {
278
+ type: "button",
279
+ onClick: () => dataEngine.delete(fieldName),
280
+ className: "text-fd-muted-foreground hover:text-fd-accent-foreground",
281
+ children: /* @__PURE__ */ jsx(X, { className: "size-3.5" })
282
+ });
283
+ }
284
+ if (info.unionField && field[info.unionField] && field[info.unionField].length > 0) {
285
+ const union = field[info.unionField];
286
+ const showSelect = union.length > 1;
287
+ return /* @__PURE__ */ jsx(FieldSet, {
288
+ ...props,
289
+ name,
290
+ fieldName,
291
+ isRequired,
292
+ field: union[info.oneOf],
293
+ depth: depth + 1,
294
+ slotType: showSelect ? false : slotType,
295
+ collapsible,
296
+ toolbar: /* @__PURE__ */ jsxs(Fragment$1, { children: [showSelect && /* @__PURE__ */ jsx("select", {
297
+ className: "text-xs font-mono",
298
+ value: info.oneOf,
299
+ onChange: (e) => {
300
+ updateInfo({ oneOf: Number(e.target.value) });
301
+ },
302
+ children: union.map((item, i) => /* @__PURE__ */ jsx("option", {
303
+ value: i,
304
+ className: "bg-fd-popover text-fd-popover-foreground",
305
+ children: stringify(item, { alias: true })
306
+ }, i))
307
+ }), toolbar] })
308
+ });
309
+ }
310
+ if (Array.isArray(field.type)) {
311
+ const showSelect = field.type.length > 1;
312
+ return /* @__PURE__ */ jsx(FieldSet, {
313
+ ...props,
314
+ name,
315
+ fieldName,
316
+ isRequired,
317
+ field: {
318
+ ...field,
319
+ type: info.selectedType
320
+ },
321
+ collapsible,
322
+ depth: depth + 1,
323
+ slotType: showSelect ? false : slotType,
324
+ toolbar: /* @__PURE__ */ jsxs(Fragment$1, { children: [showSelect && /* @__PURE__ */ jsx("select", {
325
+ className: "text-xs font-mono",
326
+ value: info.selectedType,
327
+ onChange: (e) => {
328
+ updateInfo({ selectedType: e.target.value });
329
+ },
330
+ children: field.type.map((item) => /* @__PURE__ */ jsx("option", {
331
+ value: item,
332
+ className: "bg-fd-popover text-fd-popover-foreground",
333
+ children: item
334
+ }, item))
335
+ }), toolbar] })
336
+ });
337
+ }
338
+ if (field.type === "object") return /* @__PURE__ */ jsxs("fieldset", {
339
+ ...props,
340
+ "data-collapsible": collapsible,
341
+ className: cn("flex flex-col gap-1.5 col-span-full @container", props.className),
342
+ children: [/* @__PURE__ */ jsxs("div", {
343
+ className: fieldLabelVariants(),
344
+ children: [
345
+ renderLabelTrigger(field),
346
+ slotType ?? /* @__PURE__ */ jsx(FieldLabelType, { children: stringify(field) }),
347
+ toolbar,
348
+ !isRequired && isDefined && renderUnsetButton()
349
+ ]
350
+ }), show && /* @__PURE__ */ jsx(ObjectInput, {
351
+ field,
352
+ fieldName,
353
+ className: "rounded-lg border border-fd-primary/20 bg-fd-background/50 p-2 shadow-sm"
354
+ })]
355
+ });
356
+ if (field.type === "array") return /* @__PURE__ */ jsxs("fieldset", {
357
+ ...props,
358
+ "data-collapsible": collapsible,
359
+ className: cn("flex flex-col gap-1.5 col-span-full", props.className),
360
+ children: [/* @__PURE__ */ jsxs("div", {
361
+ className: fieldLabelVariants(),
362
+ children: [
363
+ renderLabelTrigger(),
364
+ slotType ?? /* @__PURE__ */ jsx(FieldLabelType, { children: stringify(field) }),
365
+ toolbar,
366
+ !isRequired && isDefined && renderUnsetButton()
367
+ ]
368
+ }), show && /* @__PURE__ */ jsx(ArrayInput, {
369
+ fieldName,
370
+ items: field.items ?? anyFields,
371
+ className: "rounded-lg border border-fd-primary/20 bg-fd-background/50 p-2 shadow-sm"
372
+ })]
373
+ });
374
+ return /* @__PURE__ */ jsxs("fieldset", {
375
+ ...props,
376
+ className: cn("flex flex-col gap-1.5", props.className),
377
+ children: [/* @__PURE__ */ jsxs("label", {
378
+ className: fieldLabelVariants(),
379
+ htmlFor: id,
380
+ children: [
381
+ renderLabelName(),
382
+ slotType ?? /* @__PURE__ */ jsx(FieldLabelType, { children: stringify(field) }),
383
+ toolbar,
384
+ !isRequired && isDefined && renderUnsetButton()
385
+ ]
386
+ }), /* @__PURE__ */ jsx(FieldInput, {
387
+ field,
388
+ fieldName,
389
+ isRequired
390
+ })]
391
+ });
392
+ }
393
+ function ArrayInput({ fieldName, items: itemSchema, ...props }) {
394
+ const name = fieldName.at(-1) ?? "";
395
+ const { generateDefault } = useSchemaUtils();
396
+ const { items, insertItem, removeItem } = useArray(fieldName);
397
+ const t = useTranslations({ note: "playground" });
398
+ return /* @__PURE__ */ jsxs("div", {
399
+ ...props,
400
+ className: cn("flex flex-col gap-2", props.className),
401
+ children: [items.map((item) => /* @__PURE__ */ jsx(FieldSet, {
402
+ name: /* @__PURE__ */ jsxs("span", {
403
+ className: "text-fd-muted-foreground",
404
+ children: [
405
+ name,
406
+ "[",
407
+ item.index,
408
+ "]"
409
+ ]
410
+ }),
411
+ field: itemSchema,
412
+ isRequired: true,
413
+ fieldName: item.field,
414
+ toolbar: /* @__PURE__ */ jsx("button", {
415
+ type: "button",
416
+ "aria-label": t("Remove Item", { note: "aria-label" }),
417
+ className: cn(buttonVariants({
418
+ variant: "outline",
419
+ size: "icon-xs"
420
+ })),
421
+ onClick: () => removeItem(item.index),
422
+ children: /* @__PURE__ */ jsx(Trash2, {})
423
+ })
424
+ }, item.index)), /* @__PURE__ */ jsxs("button", {
425
+ type: "button",
426
+ className: cn(buttonVariants({
427
+ variant: "secondary",
428
+ className: "gap-1.5 py-2",
429
+ size: "sm"
430
+ })),
431
+ onClick: () => {
432
+ insertItem(generateDefault(itemSchema));
433
+ },
434
+ children: [/* @__PURE__ */ jsx(Plus, { className: "size-4" }), t("New Item")]
435
+ })]
436
+ });
437
+ }
438
+ //#endregion
439
+ export { FieldInput, FieldSet, JsonInput, ObjectInput };
@@ -0,0 +1,112 @@
1
+ import { createContext, use, useMemo } from "react";
2
+ import { dereference, matches, matchesType, mergeAllOf, sample } from "@fumadocs/json-schema";
3
+ import { jsx } from "react/jsx-runtime";
4
+ import { useDataEngine, useFieldValue, useNamespace } from "@fumari/stf";
5
+ import { stringifyFieldKey } from "@fumari/stf/lib/utils";
6
+ //#region ../shared-api/dist/components/playground/schema.js
7
+ const SchemaContext = createContext(void 0);
8
+ const anyFields = {
9
+ type: [
10
+ "string",
11
+ "number",
12
+ "boolean",
13
+ "array",
14
+ "object"
15
+ ],
16
+ items: true,
17
+ additionalProperties: true
18
+ };
19
+ function SchemaProvider({ readOnly, writeOnly, docRoot, children }) {
20
+ return /* @__PURE__ */ jsx(SchemaContext.Provider, {
21
+ value: useMemo(() => ({
22
+ readOnly,
23
+ writeOnly,
24
+ docRoot
25
+ }), [
26
+ docRoot,
27
+ readOnly,
28
+ writeOnly
29
+ ]),
30
+ children
31
+ });
32
+ }
33
+ function useSchemaContext() {
34
+ return use(SchemaContext);
35
+ }
36
+ /**
37
+ * A hook to store dynamic info of a field, such as selected schema of `oneOf`.
38
+ *
39
+ * @param fieldName - field name of form.
40
+ * @param schema - The **resolved** JSON Schema to generate initial values.
41
+ * @param depth - The depth to avoid duplicated field name with same schema (e.g. nested `oneOf`).
42
+ */
43
+ function useFieldInfo(fieldName, schema, depth = 0) {
44
+ const engine = useDataEngine();
45
+ const { generateDefault } = useSchemaUtils();
46
+ const fieldData = useNamespace({
47
+ namespace: `field-info:${depth}:${stringifyFieldKey(fieldName)}`,
48
+ initial() {
49
+ const value = engine.get(fieldName);
50
+ const out = { oneOf: -1 };
51
+ const union = getUnion(schema);
52
+ if (union) {
53
+ const [members, field] = union;
54
+ out.oneOf = members.findIndex((item) => typeof item === "object" && matches(item, value));
55
+ if (out.oneOf === -1) out.oneOf = 0;
56
+ out.unionField = field;
57
+ }
58
+ if (Array.isArray(schema.type)) {
59
+ const types = schema.type;
60
+ out.selectedType = types.find((type) => matchesType(value, type)) ?? types[0];
61
+ }
62
+ return out;
63
+ }
64
+ });
65
+ const [info, setInfo] = useFieldValue([], { stf: fieldData });
66
+ return {
67
+ info,
68
+ schema,
69
+ updateInfo(value) {
70
+ const updated = {
71
+ ...info,
72
+ ...value
73
+ };
74
+ if (updated.oneOf === info.oneOf && updated.selectedType === info.selectedType) return;
75
+ setInfo(updated);
76
+ let valueSchema = schema;
77
+ if (updated.unionField) valueSchema = schema[updated.unionField][updated.oneOf];
78
+ else if (updated.selectedType) valueSchema = {
79
+ ...schema,
80
+ type: updated.selectedType,
81
+ examples: void 0
82
+ };
83
+ engine.update(fieldName, generateDefault(valueSchema));
84
+ }
85
+ };
86
+ }
87
+ function useSchemaUtils() {
88
+ const { readOnly } = useSchemaContext();
89
+ return { generateDefault(schema) {
90
+ return sample(schema, {
91
+ skipNonRequired: true,
92
+ skipReadOnly: !readOnly,
93
+ quiet: true
94
+ });
95
+ } };
96
+ }
97
+ /**
98
+ * dereference & merge `allOf`.
99
+ */
100
+ function useResolvedSchema(raw) {
101
+ return useMemo(() => {
102
+ let out = dereference(raw);
103
+ if (typeof out === "object" && out.allOf) out = mergeAllOf(out);
104
+ return typeof out === "boolean" ? anyFields : out;
105
+ }, [raw]);
106
+ }
107
+ function getUnion(schema) {
108
+ if (schema.anyOf) return [schema.anyOf, "anyOf"];
109
+ if (schema.oneOf) return [schema.oneOf, "oneOf"];
110
+ }
111
+ //#endregion
112
+ export { SchemaProvider, anyFields, useFieldInfo, useResolvedSchema, useSchemaContext, useSchemaUtils };
@@ -0,0 +1,23 @@
1
+ "use client";
2
+ import { cn } from "../utils/cn.js";
3
+ import "react";
4
+ import { jsx } from "react/jsx-runtime";
5
+ import { Popover } from "@base-ui/react/popover";
6
+ //#region ../shared-api/dist/components/popover.js
7
+ const Popover$1 = Popover.Root;
8
+ const PopoverTrigger = Popover.Trigger;
9
+ function PopoverContent({ className, align = "center", sideOffset = 4, ...props }) {
10
+ return /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(Popover.Positioner, {
11
+ align,
12
+ side: "bottom",
13
+ sideOffset,
14
+ className: "z-50",
15
+ children: /* @__PURE__ */ jsx(Popover.Popup, {
16
+ className: (s) => cn("z-50 origin-(--transform-origin) overflow-y-auto max-h-(--available-height) min-w-[240px] max-w-[98vw] rounded-xl border bg-fd-popover/60 backdrop-blur-lg p-2 text-sm text-fd-popover-foreground shadow-lg focus-visible:outline-none data-[closed]:animate-fd-popover-out data-[open]:animate-fd-popover-in", typeof className === "function" ? className(s) : className),
17
+ ...props
18
+ })
19
+ }) });
20
+ }
21
+ Popover.Close;
22
+ //#endregion
23
+ export { Popover$1 as Popover, PopoverContent, PopoverTrigger };
@@ -0,0 +1,12 @@
1
+ import { ReactNode } from "react";
2
+ import { SchemaUIGeneratedData } from "@fumadocs/json-schema/react";
3
+ //#region ../shared-api/dist/components/schema/client.d.ts
4
+ export interface SchemaUIProps {
5
+ /** anchor ID of the root schema, links to a property are resolved against it */
6
+ rootId: string;
7
+ name: string;
8
+ required?: boolean;
9
+ as?: 'property' | 'body';
10
+ generated: SchemaUIGeneratedData;
11
+ }
12
+ //#endregion