fumadocs-openapi 11.4.2 → 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 (125) 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/csharp.js +0 -1
  54. package/dist/requests/generators/go.js +0 -1
  55. package/dist/requests/generators/index.d.ts +4 -4
  56. package/dist/requests/generators/index.js +2 -2
  57. package/dist/requests/generators/java.js +0 -1
  58. package/dist/requests/generators/javascript.js +0 -1
  59. package/dist/requests/generators/python.js +0 -1
  60. package/dist/requests/generators/rust.js +0 -1
  61. package/dist/requests/index.d.ts +4 -0
  62. package/dist/requests/index.js +3 -0
  63. package/dist/requests/media/adapter.d.ts +1 -0
  64. package/dist/requests/media/encode.d.ts +7 -2
  65. package/dist/requests/media/resolve-adapter.d.ts +20 -0
  66. package/dist/server/index.d.ts +4 -7
  67. package/dist/server/index.js +1 -7
  68. package/dist/types.d.ts +0 -14
  69. package/dist/ui/base.d.ts +3 -2
  70. package/dist/ui/base.js +15 -166
  71. package/dist/ui/components/codeblock.js +3 -10
  72. package/dist/ui/components/heading.js +10 -19
  73. package/dist/ui/components/markdown.js +4 -6
  74. package/dist/ui/components/method-label.js +2 -17
  75. package/dist/ui/components/schema.js +28 -0
  76. package/dist/ui/index.d.ts +7 -198
  77. package/dist/ui/index.js +1 -3
  78. package/dist/ui/operation/index.js +143 -231
  79. package/dist/ui/operation/request-tabs.js +15 -23
  80. package/dist/ui/operation/response-tabs.js +9 -53
  81. package/dist/ui/operation/usage-tabs.js +35 -93
  82. package/dist/{playground → ui/playground}/client.d.ts +10 -21
  83. package/dist/ui/playground/client.js +432 -0
  84. package/dist/{playground → ui/playground}/components/oauth-dialog.js +27 -92
  85. package/dist/{playground → ui/playground}/components/result-display.d.ts +2 -2
  86. package/dist/{playground → ui/playground}/components/result-display.js +7 -7
  87. package/dist/{playground → ui/playground}/components/server-select.js +12 -13
  88. package/dist/{playground → ui/playground}/status-info.js +2 -2
  89. package/dist/{scalar → ui/scalar}/client.js +8 -6
  90. package/dist/{scalar → ui/scalar}/index.d.ts +2 -2
  91. package/dist/{scalar → ui/scalar}/index.js +3 -7
  92. package/dist/utils/create-page.d.ts +216 -0
  93. package/dist/utils/create-page.js +221 -0
  94. package/dist/utils/document/dereference.d.ts +2 -2
  95. package/dist/utils/document/dereference.js +8 -3
  96. package/dist/utils/document/load.js +2 -2
  97. package/dist/utils/get-example-requests.js +11 -13
  98. package/dist/utils/pages/builder.d.ts +15 -2
  99. package/dist/utils/pages/builder.js +6 -6
  100. package/dist/utils/pages/preset-auto.d.ts +1 -1
  101. package/dist/utils/pages/preset-auto.js +3 -3
  102. package/dist/utils/pages/to-static-data.js +4 -4
  103. package/dist/utils/pages/to-text.d.ts +1 -1
  104. package/dist/utils/pages/to-text.js +3 -5
  105. package/dist/utils/schema.js +5 -5
  106. package/dist/utils/use-server.d.ts +24 -0
  107. package/dist/utils/use-server.js +57 -0
  108. package/package.json +31 -20
  109. 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
  110. 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
  111. 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
  112. package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/helpers/traverse.js +0 -25
  113. package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/upgrade.js +0 -15
  114. package/dist/playground/client.js +0 -574
  115. package/dist/ui/contexts/api.d.ts +0 -17
  116. package/dist/ui/contexts/api.js +0 -84
  117. package/dist/ui/create-client.d.ts +0 -9
  118. package/dist/ui/create-client.js +0 -7
  119. package/dist/ui/operation/context.d.ts +0 -15
  120. package/dist/ui/operation/context.js +0 -48
  121. package/dist/ui/operation/request-tabs.d.ts +0 -12
  122. package/dist/ui/operation/response-tabs.d.ts +0 -30
  123. package/dist/utils/get-example-requests.d.ts +0 -11
  124. package/dist/utils/schema.d.ts +0 -3
  125. package/dist/utils/storage-key.js +0 -15
@@ -0,0 +1,508 @@
1
+ "use client";
2
+ import { cn } from "../../utils/cn.js";
3
+ import { Popover, PopoverContent, PopoverTrigger } from "../popover.js";
4
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../select.js";
5
+ import { mergeRefs } from "../../utils/merge-refs.js";
6
+ import { Fragment, Suspense, createContext, use, useCallback, useDeferredValue, useEffect, useMemo, useRef, useState } from "react";
7
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
+ import { useTranslations } from "@fuma-translate/react";
9
+ import { CheckIcon, FilterIcon, LinkIcon } from "lucide-react";
10
+ import { cva } from "class-variance-authority";
11
+ import { buttonVariants } from "fumadocs-ui/components/ui/button";
12
+ import { useCopyButton } from "fumadocs-ui/utils/use-copy-button";
13
+ //#region ../shared-api/dist/components/schema/client.js
14
+ const SchemaUIContext = createContext(null);
15
+ /** roots that already restored their path from the URL */
16
+ const restored = /* @__PURE__ */ new Set();
17
+ function SchemaUIProvider({ rootId, name, generated, children }) {
18
+ const [path, setPath] = useState(() => [{
19
+ $ref: generated.$root,
20
+ name
21
+ }]);
22
+ useEffect(() => {
23
+ if (restored.has(rootId)) return;
24
+ const url = new URL(window.location.href);
25
+ const param = url.searchParams.get("path");
26
+ if (url.hash !== `#${rootId}` || !param) return;
27
+ const decoded = decodePath(param, url.searchParams.get("s-highlight"));
28
+ if (decoded.length === 0 || decoded.some((item) => !generated.refs[item.$ref])) return;
29
+ setPath(decoded);
30
+ restored.add(rootId);
31
+ if (!decoded.at(-1).highlighted) document.getElementById(rootId)?.scrollIntoView({ behavior: "smooth" });
32
+ }, [rootId, generated.refs]);
33
+ return /* @__PURE__ */ jsx(SchemaUIContext, {
34
+ value: useMemo(() => ({
35
+ rootId,
36
+ path,
37
+ setPath,
38
+ generated,
39
+ open: (name, $ref) => setPath([...path, {
40
+ name,
41
+ $ref
42
+ }]),
43
+ back: (index) => setPath(path.slice(0, index + 1))
44
+ }), [
45
+ rootId,
46
+ path,
47
+ generated
48
+ ]),
49
+ children
50
+ });
51
+ }
52
+ function usePathState() {
53
+ const ctx = use(SchemaUIContext);
54
+ if (!ctx) throw new Error("Component must be used under <SchemaUIProvider />");
55
+ return ctx;
56
+ }
57
+ function useSchemaUI() {
58
+ return usePathState();
59
+ }
60
+ /**
61
+ * The selected member of a union schema on the path item at `pathIndex`, `depth` for nested unions.
62
+ */
63
+ function useSchemaTabs(pathIndex, depth) {
64
+ const { path, setPath } = usePathState();
65
+ return [path[pathIndex].tabValues?.[depth] || void 0, (value) => {
66
+ const tabValues = path[pathIndex].tabValues?.slice(0, depth) ?? [];
67
+ tabValues[depth] = value;
68
+ setPath(path.with(pathIndex, {
69
+ ...path[pathIndex],
70
+ tabValues
71
+ }));
72
+ }];
73
+ }
74
+ /**
75
+ * Open state of the popover showing the schema `$ref` of the root property `pathName`.
76
+ */
77
+ function useSchemaPopover(pathName, $ref) {
78
+ const { path, setPath } = usePathState();
79
+ return {
80
+ open: path.length > 1 && path[1].$ref === $ref && path[1].name === pathName && !path[0].closed,
81
+ onOpenChange(open) {
82
+ if (open) setPath([{
83
+ ...path[0],
84
+ closed: false
85
+ }, {
86
+ name: pathName,
87
+ $ref
88
+ }]);
89
+ else setPath(path.map((item, i) => i === 0 ? {
90
+ ...item,
91
+ closed: true
92
+ } : item));
93
+ }
94
+ };
95
+ }
96
+ /**
97
+ * Whether the property `name` on the path item at `pathIndex` is highlighted by the link it was opened from.
98
+ *
99
+ * @returns the state and a ref to scroll the highlighted element into view
100
+ */
101
+ function useSchemaHighlight(pathIndex, name) {
102
+ const { path } = usePathState();
103
+ const item = path[pathIndex];
104
+ const highlighted = item.highlighted === name;
105
+ return [highlighted, useCallback((element) => {
106
+ if (!element || !highlighted) return;
107
+ window.setTimeout(() => {
108
+ element.scrollIntoView({
109
+ behavior: "smooth",
110
+ block: "end"
111
+ });
112
+ delete item.highlighted;
113
+ }, 300);
114
+ }, [item, highlighted])];
115
+ }
116
+ /**
117
+ * Copy the link to the property `name` of the current path.
118
+ */
119
+ function useCopySchemaLink(name) {
120
+ const { path, rootId } = usePathState();
121
+ return useCopyButton(() => {
122
+ const url = new URL(window.location.href);
123
+ url.hash = `#${rootId}`;
124
+ url.searchParams.set("s-highlight", name);
125
+ url.searchParams.set("path", encodePath(path));
126
+ return navigator.clipboard.writeText(url.href);
127
+ });
128
+ }
129
+ function encodePath(path) {
130
+ return path.map((item) => [
131
+ item.name,
132
+ item.$ref,
133
+ ...item.tabValues ?? []
134
+ ].join("\0")).join("|");
135
+ }
136
+ function decodePath(path, highlighted) {
137
+ const out = [];
138
+ for (const part of path.split("|")) {
139
+ const [name, $ref, ...tabValues] = part.split("\0");
140
+ out.push({
141
+ name,
142
+ $ref,
143
+ tabValues
144
+ });
145
+ }
146
+ if (highlighted && out.length > 0) out[out.length - 1].highlighted = highlighted;
147
+ return out;
148
+ }
149
+ const typeVariants = cva("text-sm text-start text-fd-muted-foreground font-mono", { variants: { variant: { trigger: "underline hover:text-fd-accent-foreground data-[popup-open]:text-fd-accent-foreground" } } });
150
+ /** how a type opens its schema: a popover from the root, navigation inside the popover */
151
+ const TriggerContext = createContext((props) => /* @__PURE__ */ jsx(RootTypeInfoTrigger, { ...props }));
152
+ const renderPopoverTrigger = (props) => /* @__PURE__ */ jsx(PopoverTypeInfoTrigger, { ...props });
153
+ function SchemaUI({ rootId, name, required = false, as = "property", generated }) {
154
+ return /* @__PURE__ */ jsx(SchemaUIProvider, {
155
+ rootId,
156
+ name,
157
+ generated,
158
+ children: /* @__PURE__ */ jsx(SchemaUIContent, {
159
+ name,
160
+ required,
161
+ as
162
+ })
163
+ });
164
+ }
165
+ function SchemaUIContent({ name, required, as }) {
166
+ const { rootId, generated } = useSchemaUI();
167
+ if (as === "property" || generated.refs[generated.$root].type === "primitive") return /* @__PURE__ */ jsx(ObjectProperty, {
168
+ id: rootId,
169
+ name,
170
+ $type: generated.$root,
171
+ parentPathIndex: 0,
172
+ required
173
+ });
174
+ return /* @__PURE__ */ jsx("div", {
175
+ id: rootId,
176
+ children: /* @__PURE__ */ jsx(PathItemBody, { pathIndex: 0 })
177
+ });
178
+ }
179
+ function RootTypeInfoTrigger({ pathName, $ref, children }) {
180
+ const { path, rootId } = useSchemaUI();
181
+ const { open, onOpenChange } = useSchemaPopover(pathName, $ref);
182
+ const popoverRef = useCallback((element) => {
183
+ if (!element) return;
184
+ element.scrollTop = scrollTops.get(getScrollKey(rootId, path)) ?? 0;
185
+ const current = parseFloat(element.style.getPropertyValue("--min-height") || "200px");
186
+ element.style.setProperty("--min-height", Math.max(element.clientHeight + 2, current) + "px");
187
+ }, [rootId, path]);
188
+ return /* @__PURE__ */ jsxs(Popover, {
189
+ open,
190
+ onOpenChange,
191
+ children: [/* @__PURE__ */ jsx(PopoverTrigger, {
192
+ className: cn(typeVariants({ variant: "trigger" })),
193
+ children
194
+ }), /* @__PURE__ */ jsx(PopoverContent, {
195
+ ref: popoverRef,
196
+ className: "w-[600px] max-w-(--available-width) min-h-(--min-height,200px) fd-scroll-container max-h-[460px] px-3 pt-0",
197
+ onScrollEnd: (e) => {
198
+ scrollTops.set(getScrollKey(rootId, path), e.target.scrollTop);
199
+ },
200
+ children: /* @__PURE__ */ jsx(SchemaUIPopover, {})
201
+ })]
202
+ });
203
+ }
204
+ /** scroll positions of opened schemas, restored when navigating back */
205
+ const scrollTops = /* @__PURE__ */ new Map();
206
+ function getScrollKey(rootId, path) {
207
+ const last = path.at(-1);
208
+ return `${rootId}\0${path.length}\0${last.name}\0${last.$ref}`;
209
+ }
210
+ function PopoverTypeInfoTrigger({ pathName, $ref, children }) {
211
+ const { open } = useSchemaUI();
212
+ return /* @__PURE__ */ jsx("button", {
213
+ className: cn(typeVariants({ variant: "trigger" })),
214
+ onClick: () => open(pathName, $ref),
215
+ children
216
+ });
217
+ }
218
+ function SchemaDescription({ schema, ...props }) {
219
+ return /* @__PURE__ */ jsxs("div", {
220
+ ...props,
221
+ className: cn("prose-no-margin py-2 empty:hidden", props.className),
222
+ children: [schema.description, schema.infoTags && schema.infoTags.length > 0 && /* @__PURE__ */ jsx("div", {
223
+ className: "flex flex-row gap-2 flex-wrap mt-2 empty:hidden",
224
+ children: schema.infoTags.map((tag, i) => /* @__PURE__ */ jsx(Fragment, { children: "node" in tag ? tag.node : "list" in tag ? /* @__PURE__ */ jsx(BlockTag, {
225
+ label: tag.label,
226
+ children: /* @__PURE__ */ jsx("ul", { children: tag.list.map((item, i) => /* @__PURE__ */ jsx("li", {
227
+ className: "font-mono list-disc list-inside ps-1 marker:text-fd-muted-foreground",
228
+ children: item
229
+ }, i)) })
230
+ }) : tag.block ? /* @__PURE__ */ jsx(BlockTag, {
231
+ label: tag.label,
232
+ children: tag.value
233
+ }) : /* @__PURE__ */ jsx(InlineTag, {
234
+ label: tag.label,
235
+ prose: tag.prose,
236
+ children: tag.value
237
+ }) }, i))
238
+ })]
239
+ });
240
+ }
241
+ function ObjectProperty({ name, $type, required, parentPathIndex, ...props }) {
242
+ const t = useTranslations({ note: "schema UI" });
243
+ const { generated: { refs } } = useSchemaUI();
244
+ const schema = refs[$type];
245
+ const [highlighted, ref] = useSchemaHighlight(parentPathIndex, name);
246
+ const [isChecked, onClick] = useCopySchemaLink(name);
247
+ return /* @__PURE__ */ jsxs("div", {
248
+ ...props,
249
+ ref: mergeRefs(props.ref, ref),
250
+ className: cn("text-sm border-t py-4 scroll-m-20 first:border-t-0", props.className),
251
+ children: [/* @__PURE__ */ jsxs("div", {
252
+ className: "flex flex-wrap items-center gap-2 not-prose",
253
+ children: [
254
+ /* @__PURE__ */ jsxs("span", {
255
+ className: "font-medium font-mono",
256
+ children: [/* @__PURE__ */ jsx("span", {
257
+ className: cn(highlighted ? "bg-fd-primary text-fd-primary-foreground rounded-sm" : "text-fd-primary", schema.deprecated && "line-through opacity-80"),
258
+ children: name
259
+ }), required ? /* @__PURE__ */ jsx("span", {
260
+ className: "text-red-400",
261
+ children: "*"
262
+ }) : /* @__PURE__ */ jsx("span", {
263
+ className: "text-fd-muted-foreground",
264
+ children: "?"
265
+ })]
266
+ }),
267
+ schema.type === "primitive" ? /* @__PURE__ */ jsx("span", {
268
+ className: cn(typeVariants()),
269
+ children: schema.aliasName
270
+ }) : /* @__PURE__ */ jsx(TypeInfoTrigger, {
271
+ pathName: name,
272
+ $ref: $type,
273
+ children: schema.aliasName
274
+ }),
275
+ /* @__PURE__ */ jsx("div", { className: "flex-1" }),
276
+ schema.deprecated && /* @__PURE__ */ jsx("span", {
277
+ className: "text-xs font-mono text-yellow-600 dark:text-yellow-400",
278
+ children: t("Deprecated")
279
+ }),
280
+ /* @__PURE__ */ jsx("button", {
281
+ className: cn(buttonVariants({
282
+ size: "icon-xs",
283
+ variant: "ghost"
284
+ }), "text-fd-muted-foreground [&_svg]:size-3.5"),
285
+ onClick,
286
+ children: isChecked ? /* @__PURE__ */ jsx(CheckIcon, {}) : /* @__PURE__ */ jsx(LinkIcon, {})
287
+ })
288
+ ]
289
+ }), /* @__PURE__ */ jsx(SchemaDescription, {
290
+ schema,
291
+ className: "pb-0"
292
+ })]
293
+ });
294
+ }
295
+ function PathItemBody({ pathIndex, asSchema, tabDepth = 0, objectSearchOverrides }) {
296
+ const { path, generated: { refs } } = useSchemaUI();
297
+ const [selected, setSelected] = useSchemaTabs(pathIndex, tabDepth);
298
+ const schema = asSchema ?? refs[path[pathIndex].$ref];
299
+ if ((schema.type === "or" || schema.type === "and") && schema.items.length > 0) {
300
+ const value = selected ?? schema.items[0].$type;
301
+ const items = schema.items.map((item) => ({
302
+ label: /* @__PURE__ */ jsx("code", {
303
+ className: "text-xs font-medium",
304
+ children: item.name
305
+ }),
306
+ value: item.$type
307
+ }));
308
+ return /* @__PURE__ */ jsxs(Select, {
309
+ items,
310
+ value,
311
+ onValueChange: (v) => v && setSelected(v),
312
+ children: [/* @__PURE__ */ jsxs("div", {
313
+ className: "flex flex-row my-2 gap-2 items-center",
314
+ children: [
315
+ /* @__PURE__ */ jsx(SchemaDescription, {
316
+ schema,
317
+ className: "flex-1 py-0"
318
+ }),
319
+ /* @__PURE__ */ jsx(SelectTrigger, {
320
+ className: "not-prose w-fit min-w-0 mb-auto *:min-w-0",
321
+ children: /* @__PURE__ */ jsx(SelectValue, {})
322
+ }),
323
+ /* @__PURE__ */ jsx(SelectContent, { children: items.map(({ label, value }) => /* @__PURE__ */ jsx(SelectItem, {
324
+ value,
325
+ children: label
326
+ }, value)) })
327
+ ]
328
+ }), /* @__PURE__ */ jsx(PathItemBody, {
329
+ asSchema: refs[value],
330
+ pathIndex,
331
+ tabDepth: tabDepth + 1
332
+ })]
333
+ });
334
+ }
335
+ if (schema.type === "object" && schema.props.length > 0) return /* @__PURE__ */ jsx(ObjectSearch, {
336
+ pathIndex,
337
+ schema,
338
+ ...objectSearchOverrides,
339
+ children: /* @__PURE__ */ jsx(SchemaDescription, { schema })
340
+ });
341
+ if (schema.type === "array") return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(SchemaDescription, { schema }), /* @__PURE__ */ jsx(ObjectProperty, {
342
+ name: "[index: integer]",
343
+ $type: schema.item.$type,
344
+ parentPathIndex: pathIndex
345
+ })] });
346
+ return /* @__PURE__ */ jsx(SchemaDescription, { schema });
347
+ }
348
+ function ObjectSearch({ variant = "default", schema, pathIndex, children }) {
349
+ const { open } = useSchemaUI();
350
+ const [search, setSearch] = useState("");
351
+ const deferredValue = useDeferredValue(search);
352
+ const firstItemRef = useRef(null);
353
+ const t = useTranslations({ note: "schema UI" });
354
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
355
+ /* @__PURE__ */ jsxs("div", {
356
+ className: cn("flex items-center bg-fd-secondary text-fd-secondary-foreground transition-colors", variant === "in-popover" && "sticky top-10 -mx-3 ps-3 border-b focus-within:[&_svg]:text-fd-primary", variant === "default" && "border rounded-md ps-2 shadow-sm focus-within:ring-2 focus-within:ring-fd-ring"),
357
+ children: [/* @__PURE__ */ jsx(FilterIcon, { className: "text-fd-muted-foreground size-3.5 transition-colors" }), /* @__PURE__ */ jsx("input", {
358
+ value: search,
359
+ "data-object-search-input": "",
360
+ onChange: (e) => setSearch(e.target.value),
361
+ placeholder: t("Filter Properties"),
362
+ className: "text-sm ps-2 py-2 flex-1 outline-none placeholder:text-fd-muted-foreground",
363
+ onKeyDown: (e) => {
364
+ if (e.key === "Enter") {
365
+ const item = firstItemRef.current;
366
+ if (item) open(item.name, item.$type);
367
+ e.preventDefault();
368
+ }
369
+ }
370
+ })]
371
+ }),
372
+ children,
373
+ /* @__PURE__ */ jsx(Suspense, { children: /* @__PURE__ */ jsx(ObjectSearchContent, {
374
+ search: deferredValue,
375
+ properties: schema.props,
376
+ firstItemRef,
377
+ empty: () => /* @__PURE__ */ jsxs("p", {
378
+ className: "text-fd-muted-foreground text-sm my-2!",
379
+ children: [
380
+ t("No property matching"),
381
+ " ",
382
+ /* @__PURE__ */ jsx("span", {
383
+ className: "text-fd-foreground font-medium",
384
+ children: `"${deferredValue}"`
385
+ })
386
+ ]
387
+ }),
388
+ render: (item) => /* @__PURE__ */ jsx(ObjectProperty, {
389
+ name: item.name,
390
+ $type: item.$type,
391
+ required: item.required,
392
+ parentPathIndex: pathIndex
393
+ }, item.name)
394
+ }) })
395
+ ] });
396
+ }
397
+ function ObjectSearchContent({ search: rawSearch, firstItemRef, properties, empty, render }) {
398
+ const filtered = useMemo(() => {
399
+ const search = rawSearch.trim().toLowerCase();
400
+ return search.length > 0 ? properties.filter((prop) => prop.name.toLowerCase().includes(search)) : properties;
401
+ }, [properties, rawSearch]);
402
+ firstItemRef.current = filtered[0] ?? null;
403
+ if (filtered.length === 0) return empty();
404
+ return filtered.map(render);
405
+ }
406
+ function InlineTag({ label, prose = false, children }) {
407
+ if (prose) return /* @__PURE__ */ jsxs("div", {
408
+ className: "inline-flex gap-2 bg-fd-secondary border rounded-lg text-xs p-1.5 shadow-md max-w-full",
409
+ children: [/* @__PURE__ */ jsx("span", {
410
+ className: "font-medium not-prose",
411
+ children: label
412
+ }), /* @__PURE__ */ jsx("span", {
413
+ className: "min-w-0 flex-1 text-fd-muted-foreground prose-sm prose-no-margin",
414
+ children
415
+ })]
416
+ });
417
+ return /* @__PURE__ */ jsxs("div", {
418
+ className: "inline-flex gap-2 bg-fd-secondary border rounded-lg text-xs p-1.5 shadow-md max-w-full not-prose",
419
+ children: [/* @__PURE__ */ jsx("span", {
420
+ className: "font-medium",
421
+ children: label
422
+ }), /* @__PURE__ */ jsx("code", {
423
+ className: "min-w-0 flex-1 text-fd-muted-foreground wrap-break-word",
424
+ children
425
+ })]
426
+ });
427
+ }
428
+ function BlockTag({ label, children }) {
429
+ return /* @__PURE__ */ jsxs("div", {
430
+ className: "flex flex-col w-full gap-2 bg-fd-secondary border rounded-lg p-1.5 shadow-md not-prose",
431
+ children: [/* @__PURE__ */ jsx("p", {
432
+ className: "font-medium text-xs",
433
+ children: label
434
+ }), children]
435
+ });
436
+ }
437
+ function SchemaUIPopover() {
438
+ const { path, back } = useSchemaUI();
439
+ const ref = useRef(null);
440
+ useEffect(() => {
441
+ ref.current?.querySelector("input[data-object-search-input]")?.focus({ preventScroll: true });
442
+ }, [path]);
443
+ return /* @__PURE__ */ jsx(TriggerContext, {
444
+ value: renderPopoverTrigger,
445
+ children: /* @__PURE__ */ jsxs("div", {
446
+ ref,
447
+ children: [/* @__PURE__ */ jsx("div", {
448
+ className: "sticky top-0 -mx-3 flex overflow-x-auto overflow-y-hidden items-center text-sm font-medium font-mono bg-fd-secondary text-fd-secondary-foreground px-3 h-10 border-b z-20",
449
+ children: path.map((item, i) => {
450
+ if (i === 0) return;
451
+ const isDuplicated = path.some((other, j) => j !== i && other.$ref === item.$ref);
452
+ let text;
453
+ const indexItemMatch = /^\[(\w+): (\w+)]$/.exec(item.name);
454
+ if (indexItemMatch) text = `[${indexItemMatch[1]}]`;
455
+ else if (i > 1) text = `.${item.name}`;
456
+ else text = item.name;
457
+ return /* @__PURE__ */ jsx("button", {
458
+ onClick: () => back(i),
459
+ className: cn("hover:underline hover:text-fd-accent-foreground", isDuplicated && "text-orange-400"),
460
+ children: text
461
+ }, i);
462
+ })
463
+ }), /* @__PURE__ */ jsx(PathItemBody, {
464
+ pathIndex: path.length - 1,
465
+ objectSearchOverrides: { variant: "in-popover" }
466
+ })]
467
+ })
468
+ });
469
+ }
470
+ function TypeInfoTrigger({ pathName, $ref, children }) {
471
+ const { generated: { refs } } = useSchemaUI();
472
+ const renderTrigger = use(TriggerContext);
473
+ const schema = refs[$ref];
474
+ if (schema.type === "primitive" && !schema.description && (!schema.infoTags || schema.infoTags.length === 0)) return /* @__PURE__ */ jsx("span", {
475
+ className: cn(typeVariants()),
476
+ children
477
+ });
478
+ if (schema.type === "and" || schema.type === "or") {
479
+ const sep = schema.type === "and" ? "&" : "|";
480
+ return /* @__PURE__ */ jsx("span", {
481
+ className: cn(typeVariants(), "flex flex-row gap-2 items-center flex-wrap"),
482
+ children: schema.items.map((item, i) => /* @__PURE__ */ jsxs(Fragment, { children: [i > 0 && /* @__PURE__ */ jsx("span", { children: sep }), /* @__PURE__ */ jsx(TypeInfoTrigger, {
483
+ pathName,
484
+ $ref: item.$type,
485
+ children: item.name
486
+ })] }, item.$type))
487
+ });
488
+ }
489
+ if (schema.type === "array") return /* @__PURE__ */ jsxs("span", {
490
+ className: cn(typeVariants(), "flex flex-row items-center flex-wrap"),
491
+ children: [
492
+ "array<",
493
+ /* @__PURE__ */ jsx(TypeInfoTrigger, {
494
+ pathName: `${pathName}[]`,
495
+ $ref: schema.item.$type,
496
+ children: refs[schema.item.$type].aliasName
497
+ }),
498
+ ">"
499
+ ]
500
+ });
501
+ return renderTrigger({
502
+ pathName,
503
+ $ref,
504
+ children
505
+ });
506
+ }
507
+ //#endregion
508
+ export { BlockTag, InlineTag, SchemaUI, SchemaUIProvider, useCopySchemaLink, useSchemaHighlight, useSchemaPopover, useSchemaTabs, useSchemaUI };
@@ -0,0 +1,9 @@
1
+ import { SchemaUIProps } from "./client.js";
2
+ import { GenerateSchemaUIOptions } from "@fumadocs/json-schema/react";
3
+ //#region ../shared-api/dist/components/schema/index.d.ts
4
+ //#region src/components/schema/index.d.ts
5
+ export interface SchemaUIOptions extends Omit<GenerateSchemaUIOptions, 'translations'> {
6
+ client: Omit<SchemaUIProps, 'generated'>;
7
+ }
8
+ //#endregion
9
+ export type { SchemaUIProps };
@@ -0,0 +1,28 @@
1
+ "use client";
2
+ import { SchemaUI } from "./client.js";
3
+ import { useMemo } from "react";
4
+ import { jsx } from "react/jsx-runtime";
5
+ import { useTranslations } from "@fuma-translate/react";
6
+ import { generateSchemaUI } from "@fumadocs/json-schema/react";
7
+ //#region ../shared-api/dist/components/schema/index.js
8
+ function Schema({ client, ...options }) {
9
+ const translations = useTranslations().translations;
10
+ const generated = useMemo(() => generateSchemaUI({
11
+ ...options,
12
+ translations
13
+ }), [
14
+ options.root,
15
+ options.readOnly,
16
+ options.writeOnly,
17
+ options.showExample,
18
+ options.renderMarkdown,
19
+ options.renderCodeblock,
20
+ translations
21
+ ]);
22
+ return /* @__PURE__ */ jsx(SchemaUI, {
23
+ ...client,
24
+ generated
25
+ });
26
+ }
27
+ //#endregion
28
+ export { Schema, SchemaUI };
@@ -0,0 +1,54 @@
1
+ "use client";
2
+ import { cn } from "../utils/cn.js";
3
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./select.js";
4
+ import { anchorIdStartsWith } from "../auto-anchor/index.js";
5
+ import { AnchorSection, useAnchorId } from "../auto-anchor/client.js";
6
+ import { createContext, use, useEffect, useMemo, useState } from "react";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ //#region ../shared-api/dist/components/select-tab.js
9
+ const Context = createContext(null);
10
+ function SelectTabs({ defaultValue, children }) {
11
+ const [value, setValue] = useState(defaultValue ?? null);
12
+ return /* @__PURE__ */ jsx(Context, {
13
+ value: useMemo(() => ({
14
+ value,
15
+ setValue
16
+ }), [value]),
17
+ children
18
+ });
19
+ }
20
+ function SelectTab({ value, anchorSegments, ...props }) {
21
+ const { value: currentValue, setValue } = use(Context);
22
+ const id = useAnchorId(anchorSegments ?? false);
23
+ useEffect(() => {
24
+ if (id && anchorIdStartsWith(window.location.hash.slice(1), id)) setValue(value);
25
+ }, [
26
+ id,
27
+ value,
28
+ setValue
29
+ ]);
30
+ if (value !== currentValue) return;
31
+ const content = /* @__PURE__ */ jsx("div", { ...props });
32
+ return anchorSegments ? /* @__PURE__ */ jsx(AnchorSection, {
33
+ segments: anchorSegments,
34
+ children: content
35
+ }) : content;
36
+ }
37
+ function SelectTabTrigger({ items, className, placeholder, ...props }) {
38
+ const { value, setValue } = use(Context);
39
+ return /* @__PURE__ */ jsxs(Select, {
40
+ items,
41
+ value,
42
+ onValueChange: setValue,
43
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
44
+ className: cn("not-prose w-fit min-w-0 *:min-w-0", className),
45
+ ...props,
46
+ children: /* @__PURE__ */ jsx(SelectValue, { placeholder })
47
+ }), /* @__PURE__ */ jsx(SelectContent, { children: items.map(({ label, value }) => /* @__PURE__ */ jsx(SelectItem, {
48
+ value,
49
+ children: label
50
+ }, value)) })]
51
+ });
52
+ }
53
+ //#endregion
54
+ export { SelectTab, SelectTabTrigger, SelectTabs };
@@ -0,0 +1,70 @@
1
+ import { cn } from "../utils/cn.js";
2
+ import "react";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { Check, ChevronDown, ChevronUp } from "lucide-react";
5
+ import { Select } from "@base-ui/react/select";
6
+ //#region ../shared-api/dist/components/select.js
7
+ const Select$1 = Select.Root;
8
+ Select.Group;
9
+ const SelectValue = Select.Value;
10
+ function SelectTrigger({ className, children, ref, ...props }) {
11
+ return /* @__PURE__ */ jsxs(Select.Trigger, {
12
+ ref,
13
+ className: cn("flex items-center w-full rounded-md border p-2 gap-2 text-start text-sm text-fd-secondary-foreground bg-fd-secondary hover:bg-fd-accent focus:outline-none focus:ring focus:ring-fd-ring disabled:cursor-not-allowed disabled:opacity-50 data-placeholder:text-fd-muted-foreground", className),
14
+ ...props,
15
+ children: [children, /* @__PURE__ */ jsx(Select.Icon, {
16
+ className: "ms-auto text-fd-muted-foreground shrink-0",
17
+ children: /* @__PURE__ */ jsx(ChevronDown, { className: "size-3.5" })
18
+ })]
19
+ });
20
+ }
21
+ function SelectScrollUpButton({ className, ref, ...props }) {
22
+ return /* @__PURE__ */ jsx(Select.ScrollUpArrow, {
23
+ ref,
24
+ className: cn("flex items-center justify-center py-1", className),
25
+ ...props,
26
+ children: /* @__PURE__ */ jsx(ChevronUp, { className: "size-4" })
27
+ });
28
+ }
29
+ function SelectScrollDownButton({ className, ref, ...props }) {
30
+ return /* @__PURE__ */ jsx(Select.ScrollDownArrow, {
31
+ ref,
32
+ className: cn("flex items-center justify-center py-1", className),
33
+ ...props,
34
+ children: /* @__PURE__ */ jsx(ChevronDown, { className: "size-4" })
35
+ });
36
+ }
37
+ function SelectContent({ className, children, align = "start", side = "bottom", sideOffset = 4, ref, ...props }) {
38
+ return /* @__PURE__ */ jsx(Select.Portal, { children: /* @__PURE__ */ jsx(Select.Positioner, {
39
+ align,
40
+ side,
41
+ sideOffset,
42
+ className: "z-50",
43
+ children: /* @__PURE__ */ jsxs(Select.Popup, {
44
+ ref,
45
+ className: cn("z-50 min-w-[calc(var(--anchor-width)+--spacing(2))] overflow-hidden rounded-lg border bg-fd-popover text-fd-popover-foreground shadow-md", className),
46
+ ...props,
47
+ children: [
48
+ /* @__PURE__ */ jsx(SelectScrollUpButton, {}),
49
+ /* @__PURE__ */ jsx(Select.List, {
50
+ className: "p-1",
51
+ children
52
+ }),
53
+ /* @__PURE__ */ jsx(SelectScrollDownButton, {})
54
+ ]
55
+ })
56
+ }) });
57
+ }
58
+ function SelectItem({ className, children, ref, ...props }) {
59
+ return /* @__PURE__ */ jsxs(Select.Item, {
60
+ ref,
61
+ className: cn("flex select-none flex-row items-center rounded-md py-1.5 px-2 text-sm outline-none data-[highlighted]:bg-fd-accent data-[highlighted]:text-fd-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className),
62
+ ...props,
63
+ children: [/* @__PURE__ */ jsx(Select.ItemText, { children }), /* @__PURE__ */ jsx(Select.ItemIndicator, {
64
+ className: "ms-auto shrink-0",
65
+ children: /* @__PURE__ */ jsx(Check, { className: "size-3.5 text-fd-primary" })
66
+ })]
67
+ });
68
+ }
69
+ //#endregion
70
+ export { Select$1 as Select, SelectContent, SelectItem, SelectScrollDownButton, SelectScrollUpButton, SelectTrigger, SelectValue };
@@ -0,0 +1,14 @@
1
+ import { cn } from "../utils/cn.js";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { Loader2Icon } from "lucide-react";
4
+ //#region ../shared-api/dist/components/spinner.js
5
+ function Spinner({ className, ...props }) {
6
+ return /* @__PURE__ */ jsx(Loader2Icon, {
7
+ role: "status",
8
+ "aria-label": "Loading",
9
+ className: cn("size-4 animate-spin", className),
10
+ ...props
11
+ });
12
+ }
13
+ //#endregion
14
+ export { Spinner };
@@ -0,0 +1,3 @@
1
+ import { Translations } from "./.translations/index.js";
2
+ import { TranslationExtension } from "fumadocs-core/i18n";
3
+ export type { Translations };