UI/modules: exclude typescript from dynamic field names and types

This commit is contained in:
Johannes Kirschbauer
2024-11-13 08:57:03 +01:00
parent ac45d03216
commit 38a980ae71
2 changed files with 56 additions and 46 deletions

View File

@@ -12,7 +12,11 @@ import { Label } from "../base/label";
import { useFloating } from "../base"; import { useFloating } from "../base";
import { autoUpdate, flip, hide, shift, size } from "@floating-ui/dom"; import { autoUpdate, flip, hide, shift, size } from "@floating-ui/dom";
export type Option = { value: string; label: string }; export interface Option {
value: string;
label: string;
}
interface SelectInputpProps { interface SelectInputpProps {
value: string[] | string; value: string[] | string;
selectProps: JSX.InputHTMLAttributes<HTMLSelectElement>; selectProps: JSX.InputHTMLAttributes<HTMLSelectElement>;
@@ -81,7 +85,7 @@ export function SelectInput(props: SelectInputpProps) {
const handleClickOption = (opt: Option) => { const handleClickOption = (opt: Option) => {
if (!props.multiple) { if (!props.multiple) {
// @ts-ignore // @ts-expect-error: fieldName is not known ahead of time
props.selectProps.onInput({ props.selectProps.onInput({
currentTarget: { currentTarget: {
value: opt.value, value: opt.value,
@@ -96,7 +100,7 @@ export function SelectInput(props: SelectInputpProps) {
} else { } else {
currValues.push(opt.value); currValues.push(opt.value);
} }
// @ts-ignore // @ts-expect-error: fieldName is not known ahead of time
props.selectProps.onInput({ props.selectProps.onInput({
currentTarget: { currentTarget: {
options: currValues.map((value) => ({ options: currValues.map((value) => ({
@@ -128,17 +132,17 @@ export function SelectInput(props: SelectInputpProps) {
{props.adornment?.content} {props.adornment?.content}
</Show> </Show>
{props.inlineLabel} {props.inlineLabel}
<div class="flex flex-row gap-2 cursor-default"> <div class="flex cursor-default flex-row gap-2">
<For each={getValues()} fallback={"Select"}> <For each={getValues()} fallback={"Select"}>
{(item) => ( {(item) => (
<div class="text-sm rounded-xl bg-slate-800 text-white px-4 py-1"> <div class="rounded-xl bg-slate-800 px-4 py-1 text-sm text-white">
{item} {item}
<Show when={props.multiple}> <Show when={props.multiple}>
<button <button
class="btn-xs btn-ghost" class="btn-ghost btn-xs"
type="button" type="button"
onClick={(_e) => { onClick={(_e) => {
// @ts-ignore // @ts-expect-error: fieldName is not known ahead of time
props.selectProps.onInput({ props.selectProps.onInput({
currentTarget: { currentTarget: {
options: getValues() options: getValues()
@@ -188,9 +192,9 @@ export function SelectInput(props: SelectInputpProps) {
top: `${position.y ?? 0}px`, top: `${position.y ?? 0}px`,
left: `${position.x ?? 0}px`, left: `${position.x ?? 0}px`,
}} }}
class="dropdown-content bg-base-100 rounded-b-box z-[1] shadow" class="dropdown-content z-[1] rounded-b-box bg-base-100 shadow"
> >
<ul class="menu flex flex-col gap-1 max-h-96 overflow-y-scroll overflow-x-hidden"> <ul class="menu flex max-h-96 flex-col gap-1 overflow-x-hidden overflow-y-scroll">
<For each={props.options}> <For each={props.options}>
{(opt) => ( {(opt) => (
<> <>

View File

@@ -36,7 +36,7 @@ import cx from "classnames";
import { Label } from "../base/label"; import { Label } from "../base/label";
import { SelectInput } from "../fields/Select"; import { SelectInput } from "../fields/Select";
function generateDefaults(schema: JSONSchema7): any { function generateDefaults(schema: JSONSchema7): unknown {
switch (schema.type) { switch (schema.type) {
case "string": case "string":
return ""; // Default value for string return ""; // Default value for string
@@ -51,11 +51,12 @@ function generateDefaults(schema: JSONSchema7): any {
case "array": case "array":
return []; // Default empty array if no items schema or items is true/false return []; // Default empty array if no items schema or items is true/false
case "object": case "object": {
const obj: { [key: string]: any } = {}; const obj: Record<string, unknown> = {};
if (schema.properties) { if (schema.properties) {
Object.entries(schema.properties).forEach(([key, propSchema]) => { Object.entries(schema.properties).forEach(([key, propSchema]) => {
if (typeof propSchema === "boolean") { if (typeof propSchema === "boolean") {
obj[key] = false;
} else { } else {
// if (schema.required schema.required.includes(key)) // if (schema.required schema.required.includes(key))
obj[key] = generateDefaults(propSchema); obj[key] = generateDefaults(propSchema);
@@ -63,6 +64,7 @@ function generateDefaults(schema: JSONSchema7): any {
}); });
} }
return obj; return obj;
}
default: default:
return null; // Default for unknown types or nulls return null; // Default for unknown types or nulls
@@ -359,7 +361,7 @@ export function ListValueDisplay<T extends FieldValues, R extends ResponseData>(
e.preventDefault(); e.preventDefault();
remove( remove(
props.formStore, props.formStore,
// @ts-ignore // @ts-expect-error: listFieldName is not known ahead of time
props.listFieldName, props.listFieldName,
{ at: props.idx }, { at: props.idx },
); );
@@ -368,7 +370,7 @@ export function ListValueDisplay<T extends FieldValues, R extends ResponseData>(
e.preventDefault(); e.preventDefault();
move( move(
props.formStore, props.formStore,
// @ts-ignore // @ts-expect-error: listFieldName is not known ahead of time
props.listFieldName, props.listFieldName,
{ from: props.idx, to: props.idx + dir }, { from: props.idx, to: props.idx + dir },
); );
@@ -377,10 +379,10 @@ export function ListValueDisplay<T extends FieldValues, R extends ResponseData>(
const bottomMost = () => props.idx === 0; const bottomMost = () => props.idx === 0;
return ( return (
<div class="border-l-4 border-gray-300 w-full"> <div class="w-full border-l-4 border-gray-300">
<div class="flex w-full gap-2 items-end px-4"> <div class="flex w-full items-end gap-2 px-4">
{props.children} {props.children}
<div class="pb-4 ml-4 min-w-fit"> <div class="ml-4 min-w-fit pb-4">
<button class="btn" onClick={moveItemBy(1)} disabled={topMost()}> <button class="btn" onClick={moveItemBy(1)} disabled={topMost()}>
</button> </button>
@@ -396,7 +398,7 @@ export function ListValueDisplay<T extends FieldValues, R extends ResponseData>(
); );
} }
const findDuplicates = (arr: any[]) => { const findDuplicates = (arr: unknown[]) => {
const seen = new Set(); const seen = new Set();
const duplicates: number[] = []; const duplicates: number[] = [];
@@ -475,20 +477,19 @@ export function ArrayFields<T extends FieldValues, R extends ResponseData>(
when={itemsSchema().type === "string" && itemsSchema().enum} when={itemsSchema().type === "string" && itemsSchema().enum}
> >
<Field <Field
// @ts-ignore // @ts-expect-error: listFieldName is not known ahead of time
name={listFieldName} name={listFieldName}
// @ts-ignore // @ts-expect-error: type is known due to schema
type="string[]" type="string[]"
validateOn="touched" validateOn="touched"
revalidateOn="touched" revalidateOn="touched"
validate={() => { validate={() => {
let error = ""; let error = "";
// @ts-ignore const values: unknown[] = getValues(
const values: any[] = getValues(
props.formStore, props.formStore,
// @ts-ignore // @ts-expect-error: listFieldName is not known ahead of time
listFieldName, listFieldName,
// @ts-ignore // @ts-expect-error: assumption based on the behavior of selectInput
)?.strings?.selection; )?.strings?.selection;
console.log("vali", { values }); console.log("vali", { values });
if (props.schema.uniqueItems) { if (props.schema.uniqueItems) {
@@ -543,17 +544,17 @@ export function ArrayFields<T extends FieldValues, R extends ResponseData>(
> >
{/* !Important: Register the parent field to gain access to array items*/} {/* !Important: Register the parent field to gain access to array items*/}
<FieldArray <FieldArray
// @ts-ignore // @ts-expect-error: listFieldName is not known ahead of time
name={listFieldName} name={listFieldName}
of={props.formStore} of={props.formStore}
validateOn="touched" validateOn="touched"
revalidateOn="touched" revalidateOn="touched"
validate={() => { validate={() => {
let error = ""; let error = "";
// @ts-ignore // @ts-expect-error: listFieldName is not known ahead of time
const values: any[] = getValues( const values: unknown[] = getValues(
props.formStore, props.formStore,
// @ts-ignore // @ts-expect-error: listFieldName is not known ahead of time
listFieldName, listFieldName,
); );
if (props.schema.uniqueItems) { if (props.schema.uniqueItems) {
@@ -596,7 +597,7 @@ export function ArrayFields<T extends FieldValues, R extends ResponseData>(
of={fieldArray.items.length} of={fieldArray.items.length}
> >
<Field <Field
// @ts-ignore: field names are not know ahead of time // @ts-expect-error: field names are not know ahead of time
name={`${listFieldName}.${idx()}`} name={`${listFieldName}.${idx()}`}
> >
{(f, fp) => ( {(f, fp) => (
@@ -642,25 +643,29 @@ export function ArrayFields<T extends FieldValues, R extends ResponseData>(
}} }}
// Add the new item to the FieldArray // Add the new item to the FieldArray
handleSubmit={(values, event) => { handleSubmit={(values, event) => {
// @ts-ignore // @ts-expect-error: listFieldName is not known ahead of time
const prev: any[] = getValues( const prev: unknown[] = getValues(
props.formStore, props.formStore,
// @ts-ignore
// @ts-expect-error: listFieldName is not known ahead of time
listFieldName, listFieldName,
); );
if (itemsSchema().type === "object") { if (itemsSchema().type === "object") {
const newIdx = prev.length; const newIdx = prev.length;
setValue( setValue(
props.formStore, props.formStore,
// @ts-ignore
// @ts-expect-error: listFieldName is not known ahead of time
`${listFieldName}.${newIdx}`, `${listFieldName}.${newIdx}`,
// @ts-ignore
// @ts-expect-error: listFieldName is not known ahead of time
values.root, values.root,
); );
} }
// @ts-ignore
// @ts-expect-error: listFieldName is not known ahead of time
insert(props.formStore, listFieldName, { insert(props.formStore, listFieldName, {
// @ts-ignore // @ts-expect-error: listFieldName is not known ahead of time
value: values.root, value: values.root,
}); });
}} }}
@@ -685,7 +690,7 @@ interface ObjectFieldPropertyLabelProps {
export function ObjectFieldPropertyLabel(props: ObjectFieldPropertyLabelProps) { export function ObjectFieldPropertyLabel(props: ObjectFieldPropertyLabelProps) {
return ( return (
<Switch fallback={props.fallback}> <Switch fallback={props.fallback}>
{/* @ts-ignore */} {/* @ts-expect-error: $exportedModuleInfo should exist since we export it */}
<Match when={props.schema?.$exportedModuleInfo?.path}> <Match when={props.schema?.$exportedModuleInfo?.path}>
{(path) => path()[path().length - 1]} {(path) => path()[path().length - 1]}
</Match> </Match>
@@ -724,6 +729,7 @@ export function ObjectFields<T extends FieldValues, R extends ResponseData>(
<For each={Object.entries(properties())}> <For each={Object.entries(properties())}>
{([propName, propSchema]) => ( {([propName, propSchema]) => (
<div <div
// eslint-disable-next-line tailwindcss/no-custom-classname
class={cx( class={cx(
"w-full grid grid-cols-1 gap-4 justify-items-start", "w-full grid grid-cols-1 gap-4 justify-items-start",
`p-${props.path.length * 2}`, `p-${props.path.length * 2}`,
@@ -780,7 +786,7 @@ export function ObjectFields<T extends FieldValues, R extends ResponseData>(
{(itemSchema) => ( {(itemSchema) => (
<Field <Field
// Important!: Register the object field to gain access to the dynamic object properties // Important!: Register the object field to gain access to the dynamic object properties
// @ts-ignore // @ts-expect-error: fieldName is not known ahead of time
name={fieldName} name={fieldName}
> >
{(objectField, fp) => ( {(objectField, fp) => (
@@ -802,11 +808,11 @@ export function ObjectFields<T extends FieldValues, R extends ResponseData>(
> >
{([key, relatedValue]) => ( {([key, relatedValue]) => (
<Field <Field
// @ts-ignore // @ts-expect-error: fieldName is not known ahead of time
name={`${fieldName}.${key}`} name={`${fieldName}.${key}`}
> >
{(f, fp) => ( {(f, fp) => (
<div class="border-l-4 border-gray-300 pl-4 w-full"> <div class="w-full border-l-4 border-gray-300 pl-4">
<DynForm <DynForm
formProps={{ formProps={{
class: cx("w-full"), class: cx("w-full"),
@@ -820,19 +826,19 @@ export function ObjectFields<T extends FieldValues, R extends ResponseData>(
{key} {key}
</span> </span>
<button <button
class="btn btn-sm btn-warning ml-auto" class="btn btn-warning btn-sm ml-auto"
type="button" type="button"
onClick={(_e) => { onClick={(_e) => {
const copy = { const copy = {
// @ts-ignore // @ts-expect-error: fieldName is not known ahead of time
...objectField.value, ...objectField.value,
}; };
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete copy[key]; delete copy[key];
setValue( setValue(
props.formStore, props.formStore,
// @ts-ignore // @ts-expect-error: fieldName is not known ahead of time
`${fieldName}`, `${fieldName}`,
// @ts-ignore
copy, copy,
); );
}} }}
@@ -862,9 +868,9 @@ export function ObjectFields<T extends FieldValues, R extends ResponseData>(
handleSubmit={(values, event) => { handleSubmit={(values, event) => {
setValue( setValue(
props.formStore, props.formStore,
// @ts-ignore // @ts-expect-error: fieldName is not known ahead of time
`${fieldName}`, `${fieldName}`,
// @ts-ignore // @ts-expect-error: fieldName is not known ahead of time
{ ...objectField.value, [values[""]]: {} }, { ...objectField.value, [values[""]]: {} },
); );
}} }}