import type { JsonError } from "json-schema-library"; import type { JSONSchema } from "json-schema-to-ts"; import { type ChangeEvent, type ReactNode, createContext, useContext, useState } from "react"; import { twMerge } from "tailwind-merge"; import * as Formy from "ui/components/form/Formy"; import { FieldComponent, Field as FormField, type FieldProps as FormFieldProps } from "./Field"; import { FormContextOverride, useFieldContext } from "./Form"; import { getLabel, getMultiSchemaMatched } from "./utils"; export type AnyOfFieldRootProps = { path?: string; schema?: Exclude; children: ReactNode; }; export type AnyOfFieldContext = { path: string; schema: Exclude; schemas?: JSONSchema[]; selectedSchema?: Exclude; selected: number | null; select: (index: number | null) => void; options: string[]; errors: JsonError[]; selectSchema: JSONSchema; }; const AnyOfContext = createContext(undefined!); export const useAnyOfContext = () => { return useContext(AnyOfContext); }; const Root = ({ path = "", schema: _schema, children }: AnyOfFieldRootProps) => { const { setValue, pointer, lib, value, errors, ...ctx } = useFieldContext(path); const schema = _schema ?? ctx.schema; if (!schema) return `AnyOfField(${path}): no schema ${pointer}`; const [matchedIndex, schemas = []] = getMultiSchemaMatched(schema, value); const [selected, setSelected] = useState(matchedIndex > -1 ? matchedIndex : null); const options = schemas.map((s, i) => s.title ?? `Option ${i + 1}`); const selectSchema = { type: "string", enum: options } satisfies JSONSchema; //console.log("AnyOf:root", { value, matchedIndex, selected, schema }); const selectedSchema = selected !== null ? (schemas[selected] as Exclude) : undefined; function select(index: number | null) { setValue(pointer, index !== null ? lib.getTemplate(undefined, schemas[index]) : undefined); setSelected(index); } return ( {/*
{JSON.stringify({ value, selected, errors: errors.length }, null, 2)}
*/} {children}
); }; const Select = () => { const { selected, select, path, schema, selectSchema } = useAnyOfContext(); function handleSelect(e: ChangeEvent) { //console.log("selected", e.target.value); const i = e.target.value ? Number(e.target.value) : null; select(i); } return ( <> {getLabel(path, schema)} ); }; const Field = ({ name, label, ...props }: Partial) => { const { selected, selectedSchema, path, errors } = useAnyOfContext(); if (selected === null) return null; return (
0 && "bg-red-500/10")}>
); }; export const AnyOf = { Root, Select, Field, useContext: useAnyOfContext }; export const AnyOfField = (props: Omit) => { return (
); };