@@ -580,10 +545,10 @@ function useAuthInputs(
),
});
} else if (security.type === 'http') {
- const fieldName = 'header.Authorization';
+ const fieldName: FieldKey = ['header', 'Authorization'];
result.push({
- fieldName: fieldName,
+ fieldName,
original: security,
defaultValue: 'Bearer ',
children: (
@@ -598,7 +563,7 @@ function useAuthInputs(
),
});
} else if (security.type === 'apiKey') {
- const fieldName = `${security.in}.${security.name}`;
+ const fieldName: FieldKey = [security.in, security.name];
result.push({
fieldName,
@@ -616,7 +581,7 @@ function useAuthInputs(
),
});
} else {
- const fieldName = 'header.Authorization';
+ const fieldName: FieldKey = ['header', 'Authorization'];
result.push({
fieldName,
@@ -650,29 +615,34 @@ function useAuthInputs(
for (const item of inputs) {
if (!item.mapOutput) continue;
-
- set(cloned, item.fieldName, item.mapOutput(get(cloned, item.fieldName)));
+ objectSet(cloned, item.fieldName, item.mapOutput(objectGet(cloned, item.fieldName)));
}
return cloned;
};
- const initAuthValues = (values: FormValues) => {
+ const initAuthValues = (stf: Stf) => {
+ const { dataEngine } = stf;
for (const item of inputs) {
const stored = localStorage.getItem(storageKeys.AuthField(item));
if (stored) {
const parsed = JSON.parse(stored);
if (typeof parsed === typeof item.defaultValue) {
- set(values, item.fieldName, parsed);
+ dataEngine.init(item.fieldName, parsed);
continue;
}
}
- set(values, item.fieldName, item.defaultValue);
+ dataEngine.init(item.fieldName, item.defaultValue);
}
- return values;
+ // reset
+ return () => {
+ for (const item of inputs) {
+ stf.dataEngine.delete(item.fieldName);
+ }
+ };
};
return { inputs, mapInputs, initAuthValues };
@@ -756,14 +726,17 @@ function CollapsiblePanel({
);
}
-// exports for customisations
export const Custom = {
- useController<
- TName extends FieldPath
= FieldPath,
- TTransformedValues = FormValues,
- >(
- props: UseControllerProps,
- ): UseControllerReturn {
- return useController(props);
+ useController(
+ fieldName: FieldKey,
+ options?: {
+ defaultValue?: unknown;
+ },
+ ) {
+ const [value, setValue] = useDataEngine().useFieldValue(fieldName, options);
+ return {
+ value,
+ setValue,
+ };
},
};
diff --git a/packages/openapi/src/playground/components/inputs.tsx b/packages/openapi/src/playground/components/inputs.tsx
index 991ff0105..d29c992af 100644
--- a/packages/openapi/src/playground/components/inputs.tsx
+++ b/packages/openapi/src/playground/components/inputs.tsx
@@ -1,7 +1,7 @@
'use client';
import { type ComponentProps, type HTMLAttributes, type ReactNode, useState } from 'react';
-import { ChevronDown, Plus, Trash2, X } from 'lucide-react';
-import { useController, useFieldArray, useFormContext } from 'react-hook-form';
+import { ChevronRight, Plus, Trash2, X } from 'lucide-react';
+import { FieldKey, useArray, useDataEngine, useObject } from '@fumari/stf';
import {
Select,
SelectContent,
@@ -16,6 +16,7 @@ import { buttonVariants } from 'fumadocs-ui/components/ui/button';
import { FormatFlags, schemaToString } from '@/utils/schema-to-string';
import { anyFields, useFieldInfo, useResolvedSchema, useSchemaScope } from '@/playground/schema';
import type { ParsedSchema } from '@/utils/schema';
+import { stringifyFieldKey } from '@fumari/stf/lib/utils';
function FieldLabel(props: ComponentProps<'label'>) {
return (
@@ -51,59 +52,97 @@ export function ObjectInput({
...props
}: {
field: Exclude;
- fieldName: string;
+ fieldName: FieldKey;
} & ComponentProps<'div'>) {
const field = useResolvedSchema(_field);
+ const [nextName, setNextName] = useState('');
+ const { properties, onAppend, onDelete } = useObject(fieldName, {
+ defaultValue: getDefaultValue(field) as object,
+ properties: field.properties ?? {},
+ fallback: field.additionalProperties,
+ patternProperties: field.patternProperties,
+ });
+ const isDynamic = field.patternProperties ?? field.additionalProperties;
return (
- {Object.entries(field.properties ?? {}).map(([key, child]) => (
-
- ))}
- {(field.additionalProperties || field.patternProperties) && (
-
!field.properties || !Object.keys(field.properties).includes(v)}
- getType={(key) => {
- for (const pattern in field.patternProperties) {
- if (key.match(RegExp(pattern))) {
- return field.patternProperties[pattern];
- }
- }
-
- if (field.additionalProperties) return field.additionalProperties;
+ {properties.map((child) => {
+ let toolbar: ReactNode = null;
+ if (child.kind === 'pattern' || child.kind === 'fallback') {
+ toolbar = (
+
+ );
+ }
- return anyFields;
- }}
- />
+ return (
+
+ );
+ })}
+ {isDynamic && (
+
+ setNextName(e.target.value)}
+ onKeyDown={(e) => {
+ if (e.key === 'Enter') {
+ setNextName('');
+ onAppend(nextName);
+ e.preventDefault();
+ }
+ }}
+ />
+
+
)}
);
}
-export function JsonInput({ fieldName }: { fieldName: string }) {
- const controller = useController({
- name: fieldName,
- });
+export function JsonInput({ fieldName }: { fieldName: FieldKey }) {
+ const engine = useDataEngine();
const [error, setError] = useState(null);
- const [value, setValue] = useState(() => JSON.stringify(controller.field.value, null, 2));
+ const [value, setValue] = useState(() => JSON.stringify(engine.init(fieldName, {}), null, 2));
return (