fumadocs-openapi 10.2.4 → 10.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/generate-file.js.map +1 -1
- package/dist/playground/client.d.ts +11 -12
- package/dist/playground/client.d.ts.map +1 -1
- package/dist/playground/client.js +70 -74
- package/dist/playground/client.js.map +1 -1
- package/dist/playground/components/inputs.js +198 -187
- package/dist/playground/components/inputs.js.map +1 -1
- package/dist/playground/components/oauth-dialog.js +2 -2
- package/dist/playground/components/server-select.js +24 -25
- package/dist/playground/components/server-select.js.map +1 -1
- package/dist/playground/fetcher.js.map +1 -1
- package/dist/playground/index.js.map +1 -1
- package/dist/playground/schema.d.ts +1 -0
- package/dist/playground/schema.d.ts.map +1 -1
- package/dist/playground/schema.js +10 -12
- package/dist/playground/schema.js.map +1 -1
- package/dist/playground/status-info.js.map +1 -1
- package/dist/requests/generators/csharp.js.map +1 -1
- package/dist/requests/generators/curl.js.map +1 -1
- package/dist/requests/generators/go.js.map +1 -1
- package/dist/requests/generators/index.js.map +1 -1
- package/dist/requests/generators/java.js.map +1 -1
- package/dist/requests/generators/javascript.js.map +1 -1
- package/dist/requests/generators/python.js.map +1 -1
- package/dist/requests/media/adapter.js.map +1 -1
- package/dist/requests/media/encode.js.map +1 -1
- package/dist/requests/media/resolve-adapter.js +4 -0
- package/dist/requests/media/resolve-adapter.js.map +1 -1
- package/dist/server/create.js.map +1 -1
- package/dist/server/proxy.js.map +1 -1
- package/dist/server/source-api.js.map +1 -1
- package/dist/ui/api-page.js.map +1 -1
- package/dist/ui/contexts/api.js.map +1 -1
- package/dist/ui/operation/index.js.map +1 -1
- package/dist/ui/operation/request-tabs.js.map +1 -1
- package/dist/ui/operation/response-tabs.js.map +1 -1
- package/dist/ui/operation/usage-tabs/client.js.map +1 -1
- package/dist/ui/operation/usage-tabs/index.js.map +1 -1
- package/dist/ui/schema/client.d.ts.map +1 -1
- package/dist/ui/schema/client.js +120 -114
- package/dist/ui/schema/client.js.map +1 -1
- package/dist/ui/schema/index.js +1 -1
- package/dist/ui/schema/index.js.map +1 -1
- package/dist/utils/id-to-title.js.map +1 -1
- package/dist/utils/merge-schema.js.map +1 -1
- package/dist/utils/pages/builder.js.map +1 -1
- package/dist/utils/pages/preset-auto.js.map +1 -1
- package/dist/utils/pages/to-static-data.js.map +1 -1
- package/dist/utils/pages/to-text.js.map +1 -1
- package/package.json +13 -12
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { cn } from "../../utils/cn.js";
|
|
4
|
+
import { getDefaultValue } from "../get-default-values.js";
|
|
5
|
+
import { anyFields, useFieldInfo, useResolvedSchema, useSchemaScope } from "../schema.js";
|
|
4
6
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../ui/components/select.js";
|
|
5
7
|
import { Input, labelVariants } from "../../ui/components/input.js";
|
|
6
|
-
import { getDefaultValue } from "../get-default-values.js";
|
|
7
8
|
import { FormatFlags, schemaToString } from "../../utils/schema-to-string.js";
|
|
8
|
-
import { anyFields, useFieldInfo, useResolvedSchema, useSchemaScope } from "../schema.js";
|
|
9
9
|
import { useState } from "react";
|
|
10
|
-
import { useController, useFieldArray, useFormContext } from "react-hook-form";
|
|
11
10
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
12
|
-
import {
|
|
11
|
+
import { ChevronRight, Plus, Trash2, X } from "lucide-react";
|
|
13
12
|
import { buttonVariants } from "fumadocs-ui/components/ui/button";
|
|
13
|
+
import { useArray, useDataEngine, useFieldValue, useObject } from "@fumari/stf";
|
|
14
|
+
import { stringifyFieldKey } from "@fumari/stf/lib/utils";
|
|
14
15
|
|
|
15
16
|
//#region src/playground/components/inputs.tsx
|
|
16
17
|
function FieldLabel(props) {
|
|
@@ -39,39 +40,79 @@ function FieldLabelType(props) {
|
|
|
39
40
|
}
|
|
40
41
|
function ObjectInput({ field: _field, fieldName, ...props }) {
|
|
41
42
|
const field = useResolvedSchema(_field);
|
|
43
|
+
const [nextName, setNextName] = useState("");
|
|
44
|
+
const { properties, onAppend, onDelete } = useObject(fieldName, {
|
|
45
|
+
defaultValue: () => getDefaultValue(field),
|
|
46
|
+
properties: field.properties ?? {},
|
|
47
|
+
fallback: field.additionalProperties,
|
|
48
|
+
patternProperties: field.patternProperties
|
|
49
|
+
});
|
|
50
|
+
const isDynamic = field.patternProperties ?? field.additionalProperties;
|
|
42
51
|
return /* @__PURE__ */ jsxs("div", {
|
|
43
52
|
...props,
|
|
44
53
|
className: cn("grid grid-cols-1 gap-4 @md:grid-cols-2", props.className),
|
|
45
|
-
children: [
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
children: [properties.map((child) => {
|
|
55
|
+
let toolbar = null;
|
|
56
|
+
if (child.kind === "pattern" || child.kind === "fallback") toolbar = /* @__PURE__ */ jsx("button", {
|
|
57
|
+
type: "button",
|
|
58
|
+
"aria-label": "Remove Item",
|
|
59
|
+
className: cn(buttonVariants({
|
|
60
|
+
color: "outline",
|
|
61
|
+
size: "icon-xs"
|
|
62
|
+
})),
|
|
63
|
+
onClick: () => {
|
|
64
|
+
onDelete(child.key);
|
|
65
|
+
},
|
|
66
|
+
children: /* @__PURE__ */ jsx(Trash2, {})
|
|
67
|
+
});
|
|
68
|
+
return /* @__PURE__ */ jsx(FieldSet, {
|
|
69
|
+
name: child.key,
|
|
70
|
+
field: child.info,
|
|
71
|
+
fieldName: child.field,
|
|
72
|
+
isRequired: field.required?.includes(child.key),
|
|
73
|
+
toolbar
|
|
74
|
+
}, child.key);
|
|
75
|
+
}), isDynamic && /* @__PURE__ */ jsxs("div", {
|
|
76
|
+
className: "flex gap-2 col-span-full",
|
|
77
|
+
children: [/* @__PURE__ */ jsx(Input, {
|
|
78
|
+
value: nextName,
|
|
79
|
+
placeholder: "Enter Property Name",
|
|
80
|
+
onChange: (e) => setNextName(e.target.value),
|
|
81
|
+
onKeyDown: (e) => {
|
|
82
|
+
if (e.key === "Enter") {
|
|
83
|
+
setNextName("");
|
|
84
|
+
onAppend(nextName);
|
|
85
|
+
e.preventDefault();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
89
|
+
type: "button",
|
|
90
|
+
className: cn(buttonVariants({
|
|
91
|
+
color: "secondary",
|
|
92
|
+
size: "sm"
|
|
93
|
+
}), "px-4"),
|
|
94
|
+
onClick: () => {
|
|
95
|
+
onAppend(nextName);
|
|
96
|
+
setNextName("");
|
|
97
|
+
},
|
|
98
|
+
children: "New"
|
|
99
|
+
})]
|
|
58
100
|
})]
|
|
59
101
|
});
|
|
60
102
|
}
|
|
61
103
|
function JsonInput({ fieldName }) {
|
|
62
|
-
const
|
|
104
|
+
const engine = useDataEngine();
|
|
63
105
|
const [error, setError] = useState(null);
|
|
64
|
-
const [value, setValue] = useState(() => JSON.stringify(
|
|
106
|
+
const [value, setValue] = useState(() => JSON.stringify(engine.init(fieldName, {}), null, 2));
|
|
65
107
|
return /* @__PURE__ */ jsxs("div", {
|
|
66
108
|
className: "flex flex-col bg-fd-secondary text-fd-secondary-foreground overflow-hidden border rounded-lg",
|
|
67
109
|
children: [/* @__PURE__ */ jsx("textarea", {
|
|
68
|
-
...controller.field,
|
|
69
110
|
value,
|
|
70
111
|
className: "p-2 h-[240px] text-sm font-mono resize-none focus-visible:outline-none",
|
|
71
112
|
onChange: (v) => {
|
|
72
113
|
setValue(v.target.value);
|
|
73
114
|
try {
|
|
74
|
-
|
|
115
|
+
engine.update(fieldName, JSON.parse(v.target.value));
|
|
75
116
|
setError(null);
|
|
76
117
|
} catch (e) {
|
|
77
118
|
if (e instanceof Error) setError(e.message);
|
|
@@ -83,112 +124,73 @@ function JsonInput({ fieldName }) {
|
|
|
83
124
|
})]
|
|
84
125
|
});
|
|
85
126
|
}
|
|
86
|
-
function DynamicProperties({ fieldName, filterKey = () => true, getType = () => anyFields }) {
|
|
87
|
-
const { control, setValue, getValues } = useFormContext();
|
|
88
|
-
const [nextName, setNextName] = useState("");
|
|
89
|
-
const [properties, setProperties] = useState(() => {
|
|
90
|
-
const value = getValues(fieldName);
|
|
91
|
-
if (value) return Object.keys(value).filter(filterKey);
|
|
92
|
-
return [];
|
|
93
|
-
});
|
|
94
|
-
const onAppend = () => {
|
|
95
|
-
const name = nextName.trim();
|
|
96
|
-
if (name.length === 0) return;
|
|
97
|
-
setProperties((p) => {
|
|
98
|
-
if (p.includes(name) || !filterKey(name)) return p;
|
|
99
|
-
const type = getType(name);
|
|
100
|
-
setValue(`${fieldName}.${name}`, getDefaultValue(type));
|
|
101
|
-
setNextName("");
|
|
102
|
-
return [...p, name];
|
|
103
|
-
});
|
|
104
|
-
};
|
|
105
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [properties.map((item) => {
|
|
106
|
-
return /* @__PURE__ */ jsx(FieldSet, {
|
|
107
|
-
name: item,
|
|
108
|
-
field: getType(item),
|
|
109
|
-
fieldName: `${fieldName}.${item}`,
|
|
110
|
-
toolbar: /* @__PURE__ */ jsx("button", {
|
|
111
|
-
type: "button",
|
|
112
|
-
"aria-label": "Remove Item",
|
|
113
|
-
className: cn(buttonVariants({
|
|
114
|
-
color: "outline",
|
|
115
|
-
size: "icon-xs"
|
|
116
|
-
})),
|
|
117
|
-
onClick: () => {
|
|
118
|
-
setProperties((p) => p.filter((prop) => prop !== item));
|
|
119
|
-
control.unregister(`${fieldName}.${item}`);
|
|
120
|
-
},
|
|
121
|
-
children: /* @__PURE__ */ jsx(Trash2, {})
|
|
122
|
-
})
|
|
123
|
-
}, item);
|
|
124
|
-
}), /* @__PURE__ */ jsxs("div", {
|
|
125
|
-
className: "flex gap-2 col-span-full",
|
|
126
|
-
children: [/* @__PURE__ */ jsx(Input, {
|
|
127
|
-
value: nextName,
|
|
128
|
-
placeholder: "Enter Property Name",
|
|
129
|
-
onChange: (e) => setNextName(e.target.value),
|
|
130
|
-
onKeyDown: (e) => {
|
|
131
|
-
if (e.key === "Enter") {
|
|
132
|
-
onAppend();
|
|
133
|
-
e.preventDefault();
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}), /* @__PURE__ */ jsx("button", {
|
|
137
|
-
type: "button",
|
|
138
|
-
className: cn(buttonVariants({
|
|
139
|
-
color: "secondary",
|
|
140
|
-
size: "sm"
|
|
141
|
-
}), "px-4"),
|
|
142
|
-
onClick: onAppend,
|
|
143
|
-
children: "New"
|
|
144
|
-
})]
|
|
145
|
-
})] });
|
|
146
|
-
}
|
|
147
127
|
function FieldInput({ field, fieldName, isRequired, ...props }) {
|
|
148
|
-
const
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
name: fieldName
|
|
152
|
-
});
|
|
128
|
+
const engine = useDataEngine();
|
|
129
|
+
const [value, setValue] = useFieldValue(fieldName);
|
|
130
|
+
const id = stringifyFieldKey(fieldName);
|
|
153
131
|
if (field.type === "null") return;
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
})),
|
|
162
|
-
children: value instanceof File ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
|
|
163
|
-
className: "text-fd-muted-foreground text-xs",
|
|
164
|
-
children: "Selected"
|
|
165
|
-
}), /* @__PURE__ */ jsx("span", {
|
|
166
|
-
className: "truncate w-0 flex-1 text-end",
|
|
167
|
-
children: value.name
|
|
168
|
-
})] }) : /* @__PURE__ */ jsx("span", {
|
|
132
|
+
function renderUnset(children) {
|
|
133
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
134
|
+
...props,
|
|
135
|
+
className: cn("flex flex-row gap-2", props.className),
|
|
136
|
+
children: [children, value !== void 0 && !isRequired && /* @__PURE__ */ jsx("button", {
|
|
137
|
+
type: "button",
|
|
138
|
+
onClick: () => engine.delete(fieldName),
|
|
169
139
|
className: "text-fd-muted-foreground",
|
|
170
|
-
children: "
|
|
171
|
-
})
|
|
172
|
-
})
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
140
|
+
children: /* @__PURE__ */ jsx(X, { className: "size-4" })
|
|
141
|
+
})]
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
if (field.type === "string" && field.format === "binary") return renderUnset(/* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("label", {
|
|
145
|
+
htmlFor: id,
|
|
146
|
+
className: cn(buttonVariants({
|
|
147
|
+
color: "secondary",
|
|
148
|
+
className: "w-full h-9 gap-2 truncate"
|
|
149
|
+
})),
|
|
150
|
+
children: value instanceof File ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
|
|
151
|
+
className: "text-fd-muted-foreground text-xs",
|
|
152
|
+
children: "Selected"
|
|
153
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
154
|
+
className: "truncate w-0 flex-1 text-end",
|
|
155
|
+
children: value.name
|
|
156
|
+
})] }) : /* @__PURE__ */ jsx("span", {
|
|
157
|
+
className: "text-fd-muted-foreground",
|
|
158
|
+
children: "Upload"
|
|
159
|
+
})
|
|
160
|
+
}), /* @__PURE__ */ jsx("input", {
|
|
161
|
+
id,
|
|
162
|
+
type: "file",
|
|
163
|
+
multiple: false,
|
|
164
|
+
onChange: (e) => {
|
|
165
|
+
if (!e.target.files || e.target.files.length === 0) return;
|
|
166
|
+
setValue(e.target.files.item(0));
|
|
167
|
+
},
|
|
168
|
+
hidden: true
|
|
169
|
+
})] }));
|
|
170
|
+
if (field.enum && field.enum.length > 0) {
|
|
171
|
+
const idx = field.enum.indexOf(value);
|
|
172
|
+
return /* @__PURE__ */ jsxs(Select, {
|
|
173
|
+
value: String(idx),
|
|
174
|
+
onValueChange: (v) => setValue(field.enum[Number(v)]),
|
|
175
|
+
children: [/* @__PURE__ */ jsx(SelectTrigger, {
|
|
176
|
+
id,
|
|
177
|
+
...props,
|
|
178
|
+
children: /* @__PURE__ */ jsx(SelectValue, {})
|
|
179
|
+
}), /* @__PURE__ */ jsxs(SelectContent, { children: [field.enum.map((item, i) => /* @__PURE__ */ jsx(SelectItem, {
|
|
180
|
+
value: String(i),
|
|
181
|
+
children: typeof item === "string" ? item : JSON.stringify(item, null, 2)
|
|
182
|
+
}, i)), !isRequired && /* @__PURE__ */ jsx(SelectItem, {
|
|
183
|
+
value: "-1",
|
|
184
|
+
children: "Unset"
|
|
185
|
+
})] })]
|
|
186
|
+
});
|
|
187
|
+
}
|
|
184
188
|
if (field.type === "boolean") return /* @__PURE__ */ jsxs(Select, {
|
|
185
189
|
value: String(value),
|
|
186
|
-
onValueChange: (value$1) =>
|
|
187
|
-
disabled: restField.disabled,
|
|
190
|
+
onValueChange: (value$1) => setValue(value$1 === "undefined" ? void 0 : value$1 === "true"),
|
|
188
191
|
children: [/* @__PURE__ */ jsx(SelectTrigger, {
|
|
189
|
-
id
|
|
190
|
-
|
|
191
|
-
...restField,
|
|
192
|
+
id,
|
|
193
|
+
...props,
|
|
192
194
|
children: /* @__PURE__ */ jsx(SelectValue, {})
|
|
193
195
|
}), /* @__PURE__ */ jsxs(SelectContent, { children: [
|
|
194
196
|
/* @__PURE__ */ jsx(SelectItem, {
|
|
@@ -206,37 +208,29 @@ function FieldInput({ field, fieldName, isRequired, ...props }) {
|
|
|
206
208
|
] })]
|
|
207
209
|
});
|
|
208
210
|
const isNumber = field.type === "integer" || field.type === "number";
|
|
209
|
-
return /* @__PURE__ */
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
else if (!isNumber) onChange(e.target.value);
|
|
221
|
-
},
|
|
222
|
-
...restField
|
|
223
|
-
}), fieldState.isDirty && /* @__PURE__ */ jsx("button", {
|
|
224
|
-
type: "button",
|
|
225
|
-
onClick: () => form.resetField(fieldName),
|
|
226
|
-
className: "text-fd-muted-foreground",
|
|
227
|
-
children: /* @__PURE__ */ jsx(X, { className: "size-4" })
|
|
228
|
-
})]
|
|
229
|
-
});
|
|
211
|
+
return renderUnset(/* @__PURE__ */ jsx(Input, {
|
|
212
|
+
id,
|
|
213
|
+
placeholder: "Enter value",
|
|
214
|
+
type: isNumber ? "number" : "text",
|
|
215
|
+
step: field.type === "integer" ? 1 : void 0,
|
|
216
|
+
value: String(value ?? ""),
|
|
217
|
+
onChange: (e) => {
|
|
218
|
+
if (isNumber) setValue(Number.isNaN(e.target.valueAsNumber) ? void 0 : e.target.valueAsNumber);
|
|
219
|
+
else if (!isNumber) setValue(e.target.value);
|
|
220
|
+
}
|
|
221
|
+
}));
|
|
230
222
|
}
|
|
231
223
|
function FieldSet({ field: _field, fieldName, toolbar, name, isRequired, depth = 0, slotType, collapsible = true, ...props }) {
|
|
232
224
|
const { readOnly, writeOnly } = useSchemaScope();
|
|
233
225
|
const field = useResolvedSchema(_field);
|
|
234
226
|
const [show, setShow] = useState(!collapsible);
|
|
235
|
-
const { info, updateInfo } = useFieldInfo(fieldName, field
|
|
227
|
+
const { info, updateInfo } = useFieldInfo(fieldName, field);
|
|
228
|
+
const id = stringifyFieldKey(fieldName);
|
|
229
|
+
const dataEngine = useDataEngine();
|
|
236
230
|
if (_field === false) return;
|
|
237
231
|
if (field.readOnly && !readOnly) return;
|
|
238
232
|
if (field.writeOnly && !writeOnly) return;
|
|
239
|
-
if (info.unionField) {
|
|
233
|
+
if (info.unionField && field[info.unionField]) {
|
|
240
234
|
const union = field[info.unionField];
|
|
241
235
|
const showSelect = union.length > 1;
|
|
242
236
|
return /* @__PURE__ */ jsx(FieldSet, {
|
|
@@ -288,44 +282,61 @@ function FieldSet({ field: _field, fieldName, toolbar, name, isRequired, depth =
|
|
|
288
282
|
}), toolbar] })
|
|
289
283
|
});
|
|
290
284
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
className: cn(buttonVariants({
|
|
295
|
-
size: "icon-xs",
|
|
296
|
-
color: "ghost",
|
|
297
|
-
className: "text-fd-muted-foreground -ms-1"
|
|
298
|
-
})),
|
|
299
|
-
children: /* @__PURE__ */ jsx(ChevronDown, { className: cn(show && "rotate-180") })
|
|
300
|
-
});
|
|
301
|
-
if (field.type === "object" || info.intersection) return /* @__PURE__ */ jsxs("fieldset", {
|
|
302
|
-
...props,
|
|
303
|
-
className: cn("flex flex-col gap-1.5 col-span-full @container", props.className),
|
|
304
|
-
children: [/* @__PURE__ */ jsxs(FieldLabel, {
|
|
305
|
-
htmlFor: fieldName,
|
|
306
|
-
children: [
|
|
307
|
-
showBn,
|
|
308
|
-
/* @__PURE__ */ jsx(FieldLabelName, {
|
|
309
|
-
required: isRequired,
|
|
310
|
-
children: name
|
|
311
|
-
}),
|
|
312
|
-
slotType ?? /* @__PURE__ */ jsx(FieldLabelType, { children: schemaToString(field) }),
|
|
313
|
-
toolbar
|
|
314
|
-
]
|
|
315
|
-
}), show && /* @__PURE__ */ jsx(ObjectInput, {
|
|
316
|
-
field: info.intersection?.merged ?? field,
|
|
317
|
-
fieldName,
|
|
285
|
+
if (field.type === "object" || info.intersection) {
|
|
286
|
+
const schema = info.intersection?.merged ?? field;
|
|
287
|
+
return /* @__PURE__ */ jsxs("fieldset", {
|
|
318
288
|
...props,
|
|
319
|
-
className: cn("
|
|
320
|
-
|
|
321
|
-
|
|
289
|
+
className: cn("flex flex-col gap-1.5 col-span-full @container", props.className),
|
|
290
|
+
children: [/* @__PURE__ */ jsxs(FieldLabel, {
|
|
291
|
+
htmlFor: id,
|
|
292
|
+
children: [
|
|
293
|
+
collapsible && /* @__PURE__ */ jsx("button", {
|
|
294
|
+
type: "button",
|
|
295
|
+
onClick: () => {
|
|
296
|
+
dataEngine.init(fieldName, getDefaultValue(schema));
|
|
297
|
+
setShow((prev) => !prev);
|
|
298
|
+
},
|
|
299
|
+
className: cn(buttonVariants({
|
|
300
|
+
size: "icon-xs",
|
|
301
|
+
color: "ghost",
|
|
302
|
+
className: "text-fd-muted-foreground -ms-1"
|
|
303
|
+
})),
|
|
304
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { className: cn(show && "rotate-90") })
|
|
305
|
+
}),
|
|
306
|
+
/* @__PURE__ */ jsx(FieldLabelName, {
|
|
307
|
+
required: isRequired,
|
|
308
|
+
children: name
|
|
309
|
+
}),
|
|
310
|
+
slotType ?? /* @__PURE__ */ jsx(FieldLabelType, { children: schemaToString(field) }),
|
|
311
|
+
toolbar
|
|
312
|
+
]
|
|
313
|
+
}), show && /* @__PURE__ */ jsx(ObjectInput, {
|
|
314
|
+
field: schema,
|
|
315
|
+
fieldName,
|
|
316
|
+
...props,
|
|
317
|
+
className: cn("rounded-lg border border-fd-primary/20 bg-fd-background/50 p-2 shadow-sm", props.className)
|
|
318
|
+
})]
|
|
319
|
+
});
|
|
320
|
+
}
|
|
322
321
|
if (field.type === "array") return /* @__PURE__ */ jsxs("fieldset", {
|
|
323
322
|
...props,
|
|
324
323
|
className: cn("flex flex-col gap-1.5 col-span-full", props.className),
|
|
325
324
|
children: [/* @__PURE__ */ jsxs(FieldLabel, {
|
|
326
|
-
htmlFor:
|
|
325
|
+
htmlFor: id,
|
|
327
326
|
children: [
|
|
328
|
-
|
|
327
|
+
collapsible && /* @__PURE__ */ jsx("button", {
|
|
328
|
+
type: "button",
|
|
329
|
+
onClick: () => {
|
|
330
|
+
dataEngine.init(fieldName, getDefaultValue(field));
|
|
331
|
+
setShow((prev) => !prev);
|
|
332
|
+
},
|
|
333
|
+
className: cn(buttonVariants({
|
|
334
|
+
size: "icon-xs",
|
|
335
|
+
color: "ghost",
|
|
336
|
+
className: "text-fd-muted-foreground -ms-1"
|
|
337
|
+
})),
|
|
338
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { className: cn(show && "rotate-90") })
|
|
339
|
+
}),
|
|
329
340
|
/* @__PURE__ */ jsx(FieldLabelName, {
|
|
330
341
|
required: isRequired,
|
|
331
342
|
children: name
|
|
@@ -344,7 +355,7 @@ function FieldSet({ field: _field, fieldName, toolbar, name, isRequired, depth =
|
|
|
344
355
|
...props,
|
|
345
356
|
className: cn("flex flex-col gap-1.5", props.className),
|
|
346
357
|
children: [/* @__PURE__ */ jsxs(FieldLabel, {
|
|
347
|
-
htmlFor:
|
|
358
|
+
htmlFor: id,
|
|
348
359
|
children: [
|
|
349
360
|
/* @__PURE__ */ jsx(FieldLabelName, {
|
|
350
361
|
required: isRequired,
|
|
@@ -360,25 +371,25 @@ function FieldSet({ field: _field, fieldName, toolbar, name, isRequired, depth =
|
|
|
360
371
|
})]
|
|
361
372
|
});
|
|
362
373
|
}
|
|
363
|
-
function ArrayInput({ fieldName, items, ...props }) {
|
|
364
|
-
const name = fieldName.
|
|
365
|
-
const {
|
|
374
|
+
function ArrayInput({ fieldName, items: itemSchema, ...props }) {
|
|
375
|
+
const name = fieldName.at(-1) ?? "";
|
|
376
|
+
const { items, insertItem, removeItem } = useArray(fieldName, { defaultValue: [] });
|
|
366
377
|
return /* @__PURE__ */ jsxs("div", {
|
|
367
378
|
...props,
|
|
368
379
|
className: cn("flex flex-col gap-2", props.className),
|
|
369
|
-
children: [
|
|
380
|
+
children: [items.map((item) => /* @__PURE__ */ jsx(FieldSet, {
|
|
370
381
|
name: /* @__PURE__ */ jsxs("span", {
|
|
371
382
|
className: "text-fd-muted-foreground",
|
|
372
383
|
children: [
|
|
373
384
|
name,
|
|
374
385
|
"[",
|
|
375
|
-
index,
|
|
386
|
+
item.index,
|
|
376
387
|
"]"
|
|
377
388
|
]
|
|
378
389
|
}),
|
|
379
|
-
field:
|
|
390
|
+
field: itemSchema,
|
|
380
391
|
isRequired: true,
|
|
381
|
-
fieldName:
|
|
392
|
+
fieldName: item.field,
|
|
382
393
|
toolbar: /* @__PURE__ */ jsx("button", {
|
|
383
394
|
type: "button",
|
|
384
395
|
"aria-label": "Remove Item",
|
|
@@ -386,10 +397,10 @@ function ArrayInput({ fieldName, items, ...props }) {
|
|
|
386
397
|
color: "outline",
|
|
387
398
|
size: "icon-xs"
|
|
388
399
|
})),
|
|
389
|
-
onClick: () =>
|
|
400
|
+
onClick: () => removeItem(item.index),
|
|
390
401
|
children: /* @__PURE__ */ jsx(Trash2, {})
|
|
391
402
|
})
|
|
392
|
-
}, item.
|
|
403
|
+
}, item.index)), /* @__PURE__ */ jsxs("button", {
|
|
393
404
|
type: "button",
|
|
394
405
|
className: cn(buttonVariants({
|
|
395
406
|
color: "secondary",
|
|
@@ -397,7 +408,7 @@ function ArrayInput({ fieldName, items, ...props }) {
|
|
|
397
408
|
size: "sm"
|
|
398
409
|
})),
|
|
399
410
|
onClick: () => {
|
|
400
|
-
|
|
411
|
+
insertItem(getDefaultValue(itemSchema));
|
|
401
412
|
},
|
|
402
413
|
children: [/* @__PURE__ */ jsx(Plus, { className: "size-4" }), "New Item"]
|
|
403
414
|
})]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inputs.js","names":["value"],"sources":["../../../src/playground/components/inputs.tsx"],"sourcesContent":["'use client';\nimport { type ComponentProps, type HTMLAttributes, type ReactNode, useState } from 'react';\nimport { ChevronDown, Plus, Trash2, X } from 'lucide-react';\nimport { useController, useFieldArray, useFormContext } from 'react-hook-form';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/ui/components/select';\nimport { Input, labelVariants } from '@/ui/components/input';\nimport { getDefaultValue } from '../get-default-values';\nimport { cn } from '@/utils/cn';\nimport { buttonVariants } from 'fumadocs-ui/components/ui/button';\nimport { FormatFlags, schemaToString } from '@/utils/schema-to-string';\nimport { anyFields, useFieldInfo, useResolvedSchema, useSchemaScope } from '@/playground/schema';\nimport type { ParsedSchema } from '@/utils/schema';\n\nfunction FieldLabel(props: ComponentProps<'label'>) {\n return (\n <label {...props} className={cn('w-full inline-flex items-center gap-0.5', props.className)}>\n {props.children}\n </label>\n );\n}\n\nfunction FieldLabelName({\n required = false,\n ...props\n}: ComponentProps<'span'> & { required?: boolean }) {\n return (\n <span {...props} className={cn(labelVariants(), 'font-mono me-auto', props.className)}>\n {props.children}\n {required && <span className=\"text-red-400/80 mx-1\">*</span>}\n </span>\n );\n}\n\nfunction FieldLabelType(props: ComponentProps<'code'>) {\n return (\n <code {...props} className={cn('text-xs text-fd-muted-foreground', props.className)}>\n {props.children}\n </code>\n );\n}\n\nexport function ObjectInput({\n field: _field,\n fieldName,\n ...props\n}: {\n field: Exclude<ParsedSchema, boolean>;\n fieldName: string;\n} & ComponentProps<'div'>) {\n const field = useResolvedSchema(_field);\n\n return (\n <div {...props} className={cn('grid grid-cols-1 gap-4 @md:grid-cols-2', props.className)}>\n {Object.entries(field.properties ?? {}).map(([key, child]) => (\n <FieldSet\n key={key}\n name={key}\n field={child}\n fieldName={`${fieldName}.${key}`}\n isRequired={field.required?.includes(key)}\n />\n ))}\n {(field.additionalProperties || field.patternProperties) && (\n <DynamicProperties\n fieldName={fieldName}\n filterKey={(v) => !field.properties || !Object.keys(field.properties).includes(v)}\n getType={(key) => {\n for (const pattern in field.patternProperties) {\n if (key.match(RegExp(pattern))) {\n return field.patternProperties[pattern];\n }\n }\n\n if (field.additionalProperties) return field.additionalProperties;\n\n return anyFields;\n }}\n />\n )}\n </div>\n );\n}\n\nexport function JsonInput({ fieldName }: { fieldName: string }) {\n const controller = useController({\n name: fieldName,\n });\n const [error, setError] = useState<string | null>(null);\n const [value, setValue] = useState(() => JSON.stringify(controller.field.value, null, 2));\n\n return (\n <div className=\"flex flex-col bg-fd-secondary text-fd-secondary-foreground overflow-hidden border rounded-lg\">\n <textarea\n {...controller.field}\n value={value}\n className=\"p-2 h-[240px] text-sm font-mono resize-none focus-visible:outline-none\"\n onChange={(v) => {\n setValue(v.target.value);\n try {\n controller.field.onChange(JSON.parse(v.target.value));\n setError(null);\n } catch (e) {\n if (e instanceof Error) setError(e.message);\n }\n }}\n />\n <p className=\"p-2 text-xs font-mono border-t text-red-400 empty:hidden\">{error}</p>\n </div>\n );\n}\n\nfunction DynamicProperties({\n fieldName,\n filterKey = () => true,\n getType = () => anyFields,\n}: {\n fieldName: string;\n filterKey?: (key: string) => boolean;\n getType: (key: string) => ParsedSchema;\n}) {\n const { control, setValue, getValues } = useFormContext();\n const [nextName, setNextName] = useState('');\n const [properties, setProperties] = useState<string[]>(() => {\n const value = getValues(fieldName);\n if (value) return Object.keys(value).filter(filterKey);\n\n return [];\n });\n\n const onAppend = () => {\n const name = nextName.trim();\n if (name.length === 0) return;\n\n setProperties((p) => {\n if (p.includes(name) || !filterKey(name)) return p;\n const type = getType(name);\n\n setValue(`${fieldName}.${name}`, getDefaultValue(type));\n setNextName('');\n return [...p, name];\n });\n };\n\n return (\n <>\n {properties.map((item) => {\n const type = getType(item);\n\n return (\n <FieldSet\n key={item}\n name={item}\n field={type}\n fieldName={`${fieldName}.${item}`}\n toolbar={\n <button\n type=\"button\"\n aria-label=\"Remove Item\"\n className={cn(\n buttonVariants({\n color: 'outline',\n size: 'icon-xs',\n }),\n )}\n onClick={() => {\n setProperties((p) => p.filter((prop) => prop !== item));\n control.unregister(`${fieldName}.${item}`);\n }}\n >\n <Trash2 />\n </button>\n }\n />\n );\n })}\n <div className=\"flex gap-2 col-span-full\">\n <Input\n value={nextName}\n placeholder=\"Enter Property Name\"\n onChange={(e) => setNextName(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n onAppend();\n e.preventDefault();\n }\n }}\n />\n <button\n type=\"button\"\n className={cn(buttonVariants({ color: 'secondary', size: 'sm' }), 'px-4')}\n onClick={onAppend}\n >\n New\n </button>\n </div>\n </>\n );\n}\n\nexport function FieldInput({\n field,\n fieldName,\n isRequired,\n ...props\n}: HTMLAttributes<HTMLElement> & {\n field: Exclude<ParsedSchema, boolean>;\n isRequired?: boolean;\n fieldName: string;\n}) {\n const form = useFormContext();\n const {\n field: { value, onChange, ...restField },\n fieldState,\n } = useController({\n control: form.control,\n name: fieldName,\n });\n\n if (field.type === 'null') return;\n\n if (field.type === 'string' && field.format === 'binary') {\n return (\n <div {...props}>\n <label\n htmlFor={fieldName}\n className={cn(\n buttonVariants({\n color: 'secondary',\n className: 'w-full h-9 gap-2 truncate',\n }),\n )}\n >\n {value instanceof File ? (\n <>\n <span className=\"text-fd-muted-foreground text-xs\">Selected</span>\n <span className=\"truncate w-0 flex-1 text-end\">{value.name}</span>\n </>\n ) : (\n <span className=\"text-fd-muted-foreground\">Upload</span>\n )}\n </label>\n <input\n id={fieldName}\n type=\"file\"\n multiple={false}\n onChange={(e) => {\n if (!e.target.files) return;\n onChange(e.target.files.item(0));\n }}\n hidden\n {...restField}\n />\n </div>\n );\n }\n\n if (field.type === 'boolean') {\n return (\n <Select\n value={String(value)}\n onValueChange={(value) => onChange(value === 'undefined' ? undefined : value === 'true')}\n disabled={restField.disabled}\n >\n <SelectTrigger id={fieldName} className={props.className} {...restField}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"true\">True</SelectItem>\n <SelectItem value=\"false\">False</SelectItem>\n {!isRequired && <SelectItem value=\"undefined\">Unset</SelectItem>}\n </SelectContent>\n </Select>\n );\n }\n\n const isNumber = field.type === 'integer' || field.type === 'number';\n\n return (\n <div {...props} className={cn('flex flex-row gap-2', props.className)}>\n <Input\n id={fieldName}\n placeholder=\"Enter value\"\n type={isNumber ? 'number' : 'text'}\n step={field.type === 'integer' ? 1 : undefined}\n value={value ?? ''}\n onChange={(e) => {\n if (isNumber && !Number.isNaN(e.target.valueAsNumber)) {\n onChange(e.target.valueAsNumber);\n } else if (!isNumber) {\n onChange(e.target.value);\n }\n }}\n {...restField}\n />\n {fieldState.isDirty && (\n <button\n type=\"button\"\n // TODO: `react-hook-form` doesn't support setting a value to `undefined` (aka remove the value), if there's a default value defined.\n // the default value is kept by `react-hook-form` internally, we cannot manipulate it.\n // hence, we can only support resetting to the default value.\n // perhaps when we migrate to Tanstack Form, we can reconsider this.\n onClick={() => form.resetField(fieldName)}\n className=\"text-fd-muted-foreground\"\n >\n <X className=\"size-4\" />\n </button>\n )}\n </div>\n );\n}\n\nexport function FieldSet({\n field: _field,\n fieldName,\n toolbar,\n name,\n isRequired,\n depth = 0,\n slotType,\n collapsible = true,\n ...props\n}: HTMLAttributes<HTMLElement> & {\n isRequired?: boolean;\n name?: ReactNode;\n field: ParsedSchema;\n fieldName: string;\n depth?: number;\n\n slotType?: ReactNode;\n toolbar?: ReactNode;\n collapsible?: boolean;\n}) {\n const { readOnly, writeOnly } = useSchemaScope();\n const field = useResolvedSchema(_field);\n const [show, setShow] = useState(!collapsible);\n const { info, updateInfo } = useFieldInfo(fieldName, field, depth);\n\n if (_field === false) return;\n if (field.readOnly && !readOnly) return;\n if (field.writeOnly && !writeOnly) return;\n\n if (info.unionField) {\n const union = field[info.unionField]!;\n const showSelect = union.length > 1;\n\n return (\n <FieldSet\n {...props}\n name={name}\n fieldName={fieldName}\n isRequired={isRequired}\n field={union[info.oneOf]}\n depth={depth + 1}\n slotType={showSelect ? false : slotType}\n toolbar={\n <>\n {showSelect && (\n <select\n className=\"text-xs font-mono\"\n value={info.oneOf}\n onChange={(e) => {\n updateInfo({\n oneOf: Number(e.target.value),\n });\n }}\n >\n {union.map((item, i) => (\n <option key={i} value={i} className=\"bg-fd-popover text-fd-popover-foreground\">\n {schemaToString(item, undefined, FormatFlags.UseAlias)}\n </option>\n ))}\n </select>\n )}\n {toolbar}\n </>\n }\n />\n );\n }\n\n if (Array.isArray(field.type)) {\n const showSelect = field.type.length > 1;\n\n return (\n <FieldSet\n {...props}\n name={name}\n fieldName={fieldName}\n isRequired={isRequired}\n field={{\n ...field,\n type: info.selectedType,\n }}\n depth={depth + 1}\n slotType={showSelect ? false : slotType}\n toolbar={\n <>\n {showSelect && (\n <select\n className=\"text-xs font-mono\"\n value={info.selectedType}\n onChange={(e) => {\n updateInfo({\n selectedType: e.target.value,\n });\n }}\n >\n {field.type.map((item) => (\n <option\n key={item}\n value={item}\n className=\"bg-fd-popover text-fd-popover-foreground\"\n >\n {item}\n </option>\n ))}\n </select>\n )}\n {toolbar}\n </>\n }\n />\n );\n }\n\n const showBn = collapsible && (\n <button\n type=\"button\"\n onClick={() => setShow((prev) => !prev)}\n className={cn(\n buttonVariants({\n size: 'icon-xs',\n color: 'ghost',\n className: 'text-fd-muted-foreground -ms-1',\n }),\n )}\n >\n <ChevronDown className={cn(show && 'rotate-180')} />\n </button>\n );\n\n if (field.type === 'object' || info.intersection) {\n return (\n <fieldset\n {...props}\n className={cn('flex flex-col gap-1.5 col-span-full @container', props.className)}\n >\n <FieldLabel htmlFor={fieldName}>\n {showBn}\n <FieldLabelName required={isRequired}>{name}</FieldLabelName>\n {slotType ?? <FieldLabelType>{schemaToString(field)}</FieldLabelType>}\n {toolbar}\n </FieldLabel>\n {show && (\n <ObjectInput\n field={info.intersection?.merged ?? field}\n fieldName={fieldName}\n {...props}\n className={cn(\n 'rounded-lg border border-fd-primary/20 bg-fd-background/50 p-2 shadow-sm',\n props.className,\n )}\n />\n )}\n </fieldset>\n );\n }\n\n if (field.type === 'array') {\n return (\n <fieldset {...props} className={cn('flex flex-col gap-1.5 col-span-full', props.className)}>\n <FieldLabel htmlFor={fieldName}>\n {showBn}\n <FieldLabelName required={isRequired}>{name}</FieldLabelName>\n {slotType ?? <FieldLabelType>{schemaToString(field)}</FieldLabelType>}\n {toolbar}\n </FieldLabel>\n {show && (\n <ArrayInput\n fieldName={fieldName}\n items={field.items ?? anyFields}\n {...props}\n className={cn(\n 'rounded-lg border border-fd-primary/20 bg-fd-background/50 p-2 shadow-sm',\n props.className,\n )}\n />\n )}\n </fieldset>\n );\n }\n return (\n <fieldset {...props} className={cn('flex flex-col gap-1.5', props.className)}>\n <FieldLabel htmlFor={fieldName}>\n <FieldLabelName required={isRequired}>{name}</FieldLabelName>\n {slotType ?? <FieldLabelType>{schemaToString(field)}</FieldLabelType>}\n {toolbar}\n </FieldLabel>\n <FieldInput field={field} fieldName={fieldName} isRequired={isRequired} />\n </fieldset>\n );\n}\n\nfunction ArrayInput({\n fieldName,\n items,\n ...props\n}: {\n fieldName: string;\n items: ParsedSchema;\n} & ComponentProps<'div'>) {\n const name = fieldName.split('.').at(-1) ?? '';\n const { fields, append, remove } = useFieldArray({\n name: fieldName,\n });\n\n return (\n <div {...props} className={cn('flex flex-col gap-2', props.className)}>\n {fields.map((item, index) => (\n <FieldSet\n key={item.id}\n name={\n <span className=\"text-fd-muted-foreground\">\n {name}[{index}]\n </span>\n }\n field={items}\n isRequired\n fieldName={`${fieldName}.${index}`}\n toolbar={\n <button\n type=\"button\"\n aria-label=\"Remove Item\"\n className={cn(\n buttonVariants({\n color: 'outline',\n size: 'icon-xs',\n }),\n )}\n onClick={() => remove(index)}\n >\n <Trash2 />\n </button>\n }\n />\n ))}\n <button\n type=\"button\"\n className={cn(\n buttonVariants({\n color: 'secondary',\n className: 'gap-1.5 py-2',\n size: 'sm',\n }),\n )}\n onClick={() => {\n append(getDefaultValue(items));\n }}\n >\n <Plus className=\"size-4\" />\n New Item\n </button>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"inputs.js","names":["value"],"sources":["../../../src/playground/components/inputs.tsx"],"sourcesContent":["'use client';\nimport { type ComponentProps, type HTMLAttributes, type ReactNode, useState } from 'react';\nimport { ChevronRight, Plus, Trash2, X } from 'lucide-react';\nimport { FieldKey, useArray, useDataEngine, useFieldValue, useObject } from '@fumari/stf';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/ui/components/select';\nimport { Input, labelVariants } from '@/ui/components/input';\nimport { getDefaultValue } from '../get-default-values';\nimport { cn } from '@/utils/cn';\nimport { buttonVariants } from 'fumadocs-ui/components/ui/button';\nimport { FormatFlags, schemaToString } from '@/utils/schema-to-string';\nimport { anyFields, useFieldInfo, useResolvedSchema, useSchemaScope } from '@/playground/schema';\nimport type { ParsedSchema } from '@/utils/schema';\nimport { stringifyFieldKey } from '@fumari/stf/lib/utils';\n\nfunction FieldLabel(props: ComponentProps<'label'>) {\n return (\n <label {...props} className={cn('w-full inline-flex items-center gap-0.5', props.className)}>\n {props.children}\n </label>\n );\n}\n\nfunction FieldLabelName({\n required = false,\n ...props\n}: ComponentProps<'span'> & { required?: boolean }) {\n return (\n <span {...props} className={cn(labelVariants(), 'font-mono me-auto', props.className)}>\n {props.children}\n {required && <span className=\"text-red-400/80 mx-1\">*</span>}\n </span>\n );\n}\n\nfunction FieldLabelType(props: ComponentProps<'code'>) {\n return (\n <code {...props} className={cn('text-xs text-fd-muted-foreground', props.className)}>\n {props.children}\n </code>\n );\n}\n\nexport function ObjectInput({\n field: _field,\n fieldName,\n ...props\n}: {\n field: Exclude<ParsedSchema, boolean>;\n fieldName: FieldKey;\n} & ComponentProps<'div'>) {\n const field = useResolvedSchema(_field);\n const [nextName, setNextName] = useState('');\n const { properties, onAppend, onDelete } = useObject(fieldName, {\n defaultValue: () => getDefaultValue(field) as object,\n properties: field.properties ?? {},\n fallback: field.additionalProperties,\n patternProperties: field.patternProperties,\n });\n\n const isDynamic = field.patternProperties ?? field.additionalProperties;\n return (\n <div {...props} className={cn('grid grid-cols-1 gap-4 @md:grid-cols-2', props.className)}>\n {properties.map((child) => {\n let toolbar: ReactNode = null;\n if (child.kind === 'pattern' || child.kind === 'fallback') {\n toolbar = (\n <button\n type=\"button\"\n aria-label=\"Remove Item\"\n className={cn(\n buttonVariants({\n color: 'outline',\n size: 'icon-xs',\n }),\n )}\n onClick={() => {\n onDelete(child.key);\n }}\n >\n <Trash2 />\n </button>\n );\n }\n\n return (\n <FieldSet\n key={child.key}\n name={child.key}\n field={child.info}\n fieldName={child.field}\n isRequired={field.required?.includes(child.key)}\n toolbar={toolbar}\n />\n );\n })}\n {isDynamic && (\n <div className=\"flex gap-2 col-span-full\">\n <Input\n value={nextName}\n placeholder=\"Enter Property Name\"\n onChange={(e) => setNextName(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n setNextName('');\n onAppend(nextName);\n e.preventDefault();\n }\n }}\n />\n <button\n type=\"button\"\n className={cn(buttonVariants({ color: 'secondary', size: 'sm' }), 'px-4')}\n onClick={() => {\n onAppend(nextName);\n setNextName('');\n }}\n >\n New\n </button>\n </div>\n )}\n </div>\n );\n}\n\nexport function JsonInput({ fieldName }: { fieldName: FieldKey }) {\n const engine = useDataEngine();\n const [error, setError] = useState<string | null>(null);\n const [value, setValue] = useState(() => JSON.stringify(engine.init(fieldName, {}), null, 2));\n\n return (\n <div className=\"flex flex-col bg-fd-secondary text-fd-secondary-foreground overflow-hidden border rounded-lg\">\n <textarea\n value={value}\n className=\"p-2 h-[240px] text-sm font-mono resize-none focus-visible:outline-none\"\n onChange={(v) => {\n setValue(v.target.value);\n try {\n engine.update(fieldName, JSON.parse(v.target.value));\n setError(null);\n } catch (e) {\n if (e instanceof Error) setError(e.message);\n }\n }}\n />\n <p className=\"p-2 text-xs font-mono border-t text-red-400 empty:hidden\">{error}</p>\n </div>\n );\n}\n\nexport function FieldInput({\n field,\n fieldName,\n isRequired,\n ...props\n}: HTMLAttributes<HTMLElement> & {\n field: Exclude<ParsedSchema, boolean>;\n isRequired?: boolean;\n fieldName: FieldKey;\n}) {\n const engine = useDataEngine();\n const [value, setValue] = useFieldValue(fieldName);\n const id = stringifyFieldKey(fieldName);\n if (field.type === 'null') return;\n\n function renderUnset(children: ReactNode) {\n return (\n <div {...props} className={cn('flex flex-row gap-2', props.className)}>\n {children}\n {value !== undefined && !isRequired && (\n <button\n type=\"button\"\n onClick={() => engine.delete(fieldName)}\n className=\"text-fd-muted-foreground\"\n >\n <X className=\"size-4\" />\n </button>\n )}\n </div>\n );\n }\n\n if (field.type === 'string' && field.format === 'binary') {\n return renderUnset(\n <>\n <label\n htmlFor={id}\n className={cn(\n buttonVariants({\n color: 'secondary',\n className: 'w-full h-9 gap-2 truncate',\n }),\n )}\n >\n {value instanceof File ? (\n <>\n <span className=\"text-fd-muted-foreground text-xs\">Selected</span>\n <span className=\"truncate w-0 flex-1 text-end\">{value.name}</span>\n </>\n ) : (\n <span className=\"text-fd-muted-foreground\">Upload</span>\n )}\n </label>\n <input\n id={id}\n type=\"file\"\n multiple={false}\n onChange={(e) => {\n if (!e.target.files || e.target.files.length === 0) return;\n setValue(e.target.files.item(0));\n }}\n hidden\n />\n </>,\n );\n }\n\n if (field.enum && field.enum.length > 0) {\n const idx = field.enum.indexOf(value);\n\n return (\n <Select value={String(idx)} onValueChange={(v) => setValue(field.enum![Number(v)])}>\n <SelectTrigger id={id} {...props}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {field.enum.map((item, i) => (\n <SelectItem key={i} value={String(i)}>\n {typeof item === 'string' ? item : JSON.stringify(item, null, 2)}\n </SelectItem>\n ))}\n {!isRequired && <SelectItem value=\"-1\">Unset</SelectItem>}\n </SelectContent>\n </Select>\n );\n }\n\n if (field.type === 'boolean') {\n return (\n <Select\n value={String(value)}\n onValueChange={(value) => setValue(value === 'undefined' ? undefined : value === 'true')}\n >\n <SelectTrigger id={id} {...props}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"true\">True</SelectItem>\n <SelectItem value=\"false\">False</SelectItem>\n {!isRequired && <SelectItem value=\"undefined\">Unset</SelectItem>}\n </SelectContent>\n </Select>\n );\n }\n\n const isNumber = field.type === 'integer' || field.type === 'number';\n return renderUnset(\n <Input\n id={id}\n placeholder=\"Enter value\"\n type={isNumber ? 'number' : 'text'}\n step={field.type === 'integer' ? 1 : undefined}\n value={String(value ?? '')}\n onChange={(e) => {\n if (isNumber) {\n setValue(Number.isNaN(e.target.valueAsNumber) ? undefined : e.target.valueAsNumber);\n } else if (!isNumber) {\n setValue(e.target.value);\n }\n }}\n />,\n );\n}\n\nexport function FieldSet({\n field: _field,\n fieldName,\n toolbar,\n name,\n isRequired,\n depth = 0,\n slotType,\n collapsible = true,\n ...props\n}: HTMLAttributes<HTMLElement> & {\n isRequired?: boolean;\n name?: ReactNode;\n field: ParsedSchema;\n fieldName: FieldKey;\n depth?: number;\n\n slotType?: ReactNode;\n toolbar?: ReactNode;\n collapsible?: boolean;\n}) {\n const { readOnly, writeOnly } = useSchemaScope();\n const field = useResolvedSchema(_field);\n const [show, setShow] = useState(!collapsible);\n const { info, updateInfo } = useFieldInfo(fieldName, field);\n const id = stringifyFieldKey(fieldName);\n const dataEngine = useDataEngine();\n\n if (_field === false) return;\n if (field.readOnly && !readOnly) return;\n if (field.writeOnly && !writeOnly) return;\n\n if (info.unionField && field[info.unionField]) {\n const union = field[info.unionField]!;\n const showSelect = union.length > 1;\n\n return (\n <FieldSet\n {...props}\n name={name}\n fieldName={fieldName}\n isRequired={isRequired}\n field={union[info.oneOf]}\n depth={depth + 1}\n slotType={showSelect ? false : slotType}\n toolbar={\n <>\n {showSelect && (\n <select\n className=\"text-xs font-mono\"\n value={info.oneOf}\n onChange={(e) => {\n updateInfo({\n oneOf: Number(e.target.value),\n });\n }}\n >\n {union.map((item, i) => (\n <option key={i} value={i} className=\"bg-fd-popover text-fd-popover-foreground\">\n {schemaToString(item, undefined, FormatFlags.UseAlias)}\n </option>\n ))}\n </select>\n )}\n {toolbar}\n </>\n }\n />\n );\n }\n\n if (Array.isArray(field.type)) {\n const showSelect = field.type.length > 1;\n\n return (\n <FieldSet\n {...props}\n name={name}\n fieldName={fieldName}\n isRequired={isRequired}\n field={{\n ...field,\n type: info.selectedType,\n }}\n depth={depth + 1}\n slotType={showSelect ? false : slotType}\n toolbar={\n <>\n {showSelect && (\n <select\n className=\"text-xs font-mono\"\n value={info.selectedType}\n onChange={(e) => {\n updateInfo({\n selectedType: e.target.value,\n });\n }}\n >\n {field.type.map((item) => (\n <option\n key={item}\n value={item}\n className=\"bg-fd-popover text-fd-popover-foreground\"\n >\n {item}\n </option>\n ))}\n </select>\n )}\n {toolbar}\n </>\n }\n />\n );\n }\n\n if (field.type === 'object' || info.intersection) {\n const schema = info.intersection?.merged ?? field;\n return (\n <fieldset\n {...props}\n className={cn('flex flex-col gap-1.5 col-span-full @container', props.className)}\n >\n <FieldLabel htmlFor={id}>\n {collapsible && (\n <button\n type=\"button\"\n onClick={() => {\n dataEngine.init(fieldName, getDefaultValue(schema));\n setShow((prev) => !prev);\n }}\n className={cn(\n buttonVariants({\n size: 'icon-xs',\n color: 'ghost',\n className: 'text-fd-muted-foreground -ms-1',\n }),\n )}\n >\n <ChevronRight className={cn(show && 'rotate-90')} />\n </button>\n )}\n <FieldLabelName required={isRequired}>{name}</FieldLabelName>\n {slotType ?? <FieldLabelType>{schemaToString(field)}</FieldLabelType>}\n {toolbar}\n </FieldLabel>\n {show && (\n <ObjectInput\n field={schema}\n fieldName={fieldName}\n {...props}\n className={cn(\n 'rounded-lg border border-fd-primary/20 bg-fd-background/50 p-2 shadow-sm',\n props.className,\n )}\n />\n )}\n </fieldset>\n );\n }\n\n if (field.type === 'array') {\n return (\n <fieldset {...props} className={cn('flex flex-col gap-1.5 col-span-full', props.className)}>\n <FieldLabel htmlFor={id}>\n {collapsible && (\n <button\n type=\"button\"\n onClick={() => {\n dataEngine.init(fieldName, getDefaultValue(field));\n setShow((prev) => !prev);\n }}\n className={cn(\n buttonVariants({\n size: 'icon-xs',\n color: 'ghost',\n className: 'text-fd-muted-foreground -ms-1',\n }),\n )}\n >\n <ChevronRight className={cn(show && 'rotate-90')} />\n </button>\n )}\n <FieldLabelName required={isRequired}>{name}</FieldLabelName>\n {slotType ?? <FieldLabelType>{schemaToString(field)}</FieldLabelType>}\n {toolbar}\n </FieldLabel>\n {show && (\n <ArrayInput\n fieldName={fieldName}\n items={field.items ?? anyFields}\n {...props}\n className={cn(\n 'rounded-lg border border-fd-primary/20 bg-fd-background/50 p-2 shadow-sm',\n props.className,\n )}\n />\n )}\n </fieldset>\n );\n }\n return (\n <fieldset {...props} className={cn('flex flex-col gap-1.5', props.className)}>\n <FieldLabel htmlFor={id}>\n <FieldLabelName required={isRequired}>{name}</FieldLabelName>\n {slotType ?? <FieldLabelType>{schemaToString(field)}</FieldLabelType>}\n {toolbar}\n </FieldLabel>\n <FieldInput field={field} fieldName={fieldName} isRequired={isRequired} />\n </fieldset>\n );\n}\n\nfunction ArrayInput({\n fieldName,\n items: itemSchema,\n ...props\n}: {\n fieldName: FieldKey;\n items: ParsedSchema;\n} & ComponentProps<'div'>) {\n const name = fieldName.at(-1) ?? '';\n const { items, insertItem, removeItem } = useArray(fieldName, {\n defaultValue: [],\n });\n\n return (\n <div {...props} className={cn('flex flex-col gap-2', props.className)}>\n {items.map((item) => (\n <FieldSet\n key={item.index}\n name={\n <span className=\"text-fd-muted-foreground\">\n {name}[{item.index}]\n </span>\n }\n field={itemSchema}\n isRequired\n fieldName={item.field}\n toolbar={\n <button\n type=\"button\"\n aria-label=\"Remove Item\"\n className={cn(\n buttonVariants({\n color: 'outline',\n size: 'icon-xs',\n }),\n )}\n onClick={() => removeItem(item.index)}\n >\n <Trash2 />\n </button>\n }\n />\n ))}\n <button\n type=\"button\"\n className={cn(\n buttonVariants({\n color: 'secondary',\n className: 'gap-1.5 py-2',\n size: 'sm',\n }),\n )}\n onClick={() => {\n insertItem(getDefaultValue(itemSchema));\n }}\n >\n <Plus className=\"size-4\" />\n New Item\n </button>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { cn } from "../../utils/cn.js";
|
|
2
|
+
import { useQuery } from "../../utils/use-query.js";
|
|
2
3
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../ui/components/select.js";
|
|
3
4
|
import { Input, labelVariants } from "../../ui/components/input.js";
|
|
4
|
-
import { useQuery } from "../../utils/use-query.js";
|
|
5
5
|
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "../../ui/components/dialog.js";
|
|
6
6
|
import { useEffect, useState } from "react";
|
|
7
|
-
import { useForm } from "react-hook-form";
|
|
8
7
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
9
8
|
import { buttonVariants } from "fumadocs-ui/components/ui/button";
|
|
9
|
+
import { useForm } from "react-hook-form";
|
|
10
10
|
|
|
11
11
|
//#region src/playground/components/oauth-dialog.tsx
|
|
12
12
|
const FlowTypes = {
|