fumadocs-openapi
Version:
Generate MDX docs for your OpenAPI spec
61 lines (60 loc) • 4.19 kB
JavaScript
'use client';
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useApiContext, useServerSelectContext } from '../ui/contexts/api.js';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '../ui/components/select.js';
import { Input, labelVariants } from '../ui/components/input.js';
import { useEffect, useState } from 'react';
import { cn } from 'fumadocs-ui/utils/cn';
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, } from '../ui/components/dialog.js';
import { resolveServerUrl, withBase } from '../utils/url.js';
import { FormProvider, useController, useForm } from 'react-hook-form';
import { useEffectEvent } from 'fumadocs-core/utils/use-effect-event';
export default function ServerSelect(props) {
const { servers } = useApiContext();
const { server, setServer, setServerVariables } = useServerSelectContext();
const [open, setOpen] = useState(false);
const [isMounted, setIsMounted] = useState(false);
useEffect(() => {
setIsMounted(true);
}, []);
if (servers.length <= 0)
return;
const serverSchema = server
? servers.find((obj) => obj.url === server.url)
: null;
return (_jsxs(Dialog, { open: open, onOpenChange: setOpen, children: [_jsx(DialogTrigger, { className: "text-xs p-3 py-2 bg-fd-muted text-fd-muted-foreground transition-colors truncate hover:bg-fd-accent hover:text-fd-accent-foreground focus-visible:outline-none", children: isMounted
? withBase(server ? resolveServerUrl(server.url, server.variables) : '/', window.location.origin)
: 'loading...' }), _jsxs(DialogContent, { ...props, children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Server URL" }), _jsx(DialogDescription, { children: "The base URL of your API endpoint." })] }), _jsxs(Select, { value: server?.url, onValueChange: setServer, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: servers.map((item) => (_jsxs(SelectItem, { value: item.url, children: [_jsx("code", { className: "text-[13px]", children: item.url }), _jsx("p", { className: "text-fd-muted-foreground", children: item.description })] }, item.url))) })] }), server?.variables && serverSchema?.variables && (_jsx(ServerSelectContent, { defaultValues: server.variables, schema: serverSchema.variables, onChange: setServerVariables }, server.url))] })] }));
}
function ServerSelectContent({ defaultValues, onChange, schema, }) {
const form = useForm({
defaultValues,
});
const onChangeDebounced = useEffectEvent(onChange);
useEffect(() => {
let timer = null;
return form.subscribe({
formState: {
values: true,
},
callback({ values }) {
if (timer !== null)
window.clearTimeout(timer);
timer = window.setTimeout(() => onChangeDebounced(values), 500);
},
});
// eslint-disable-next-line react-hooks/exhaustive-deps -- `form` shouldn't be included
}, []);
return (_jsx(FormProvider, { ...form, children: _jsx("div", { className: "flex flex-col gap-4", children: Object.entries(schema).map(([key, variable]) => {
return (_jsxs("fieldset", { className: "flex flex-col gap-1", children: [_jsx("label", { className: cn(labelVariants()), htmlFor: key, children: key }), _jsx("p", { className: "text-xs text-fd-muted-foreground empty:hidden", children: variable.description }), _jsx(Field, { fieldName: key, variable: variable })] }, key));
}) }) }));
}
function Field({ fieldName, variable, }) {
const { field } = useController({
name: fieldName,
});
if (variable.enum) {
return (_jsxs(Select, { value: field.value, onValueChange: field.onChange, children: [_jsx(SelectTrigger, { id: fieldName, ref: field.ref, children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: variable.enum.map((value) => (_jsx(SelectItem, { value: value, children: value }, value))) })] }));
}
return _jsx(Input, { id: fieldName, ...field });
}