diff --git a/frontend/__tests__/components/ui/form/InputField.spec.tsx b/frontend/__tests__/components/ui/form/InputField.spec.tsx index 95f269accc50..7b052bb4a94b 100644 --- a/frontend/__tests__/components/ui/form/InputField.spec.tsx +++ b/frontend/__tests__/components/ui/form/InputField.spec.tsx @@ -1,12 +1,13 @@ import { render, screen, fireEvent } from "@solidjs/testing-library"; import { AnyFieldApi } from "@tanstack/solid-form"; import { describe, it, expect, vi } from "vitest"; +import { z } from "zod"; import { InputField } from "../../../../src/ts/components/ui/form/InputField"; function makeField( name: string, - value?: string | number | boolean, + value?: string | number | boolean | Date, ): AnyFieldApi { let current = value; const meta = { @@ -173,4 +174,67 @@ describe("InputField", () => { fireEvent.input(input, { target: { value: "6" } }); expect(field.handleChange).toHaveBeenCalledWith(6); }); + + it("keeps empty string for string values", async () => { + const field = makeField("age", "test"); + render(() => field} />); + const input = screen.getByRole("textbox"); + + fireEvent.input(input, { target: { value: "" } }); + fireEvent.blur(input); + + expect(field.handleChange).toHaveBeenCalledWith(""); + }); + + it("handles empty string for numeric fields", async () => { + const field = makeField("age", 5); + render(() => field} type="number" />); + const input = screen.getByRole("spinbutton"); + + fireEvent.input(input, { target: { value: "" } }); + fireEvent.blur(input); + + expect(field.handleChange).toHaveBeenCalledWith(undefined); + }); + + it("applies number schema constraints", async () => { + const field = makeField("value", 10); + const schema = z.number().min(1).max(100).int(); + render(() => ( + field} type="number" schema={schema} /> + )); + + const input = screen.getByRole("spinbutton"); + expect(input).toHaveAttribute("min", "1"); + expect(input).toHaveAttribute("max", "100"); + expect(input).toHaveAttribute("step", "1"); + }); + + it("applies float number schema constraints", async () => { + const field = makeField("value", 1.5); + const schema = z.number().min(0.5).max(10.5); + render(() => ( + field} type="number" schema={schema} /> + )); + + const input = screen.getByRole("spinbutton"); + expect(input).toHaveAttribute("min", "0.5"); + expect(input).toHaveAttribute("max", "10.5"); + expect(input).toHaveAttribute("step", "any"); + }); + + it("applies date schema constraints", async () => { + const field = makeField("date", new Date("2024-01-15")); + const schema = z + .date() + .min(new Date("2024-01-01")) + .max(new Date("2024-12-31")); + const { container } = render(() => ( + field} type="date" schema={schema} /> + )); + + const input = container.querySelector("input") as HTMLInputElement; + expect(input).toHaveAttribute("min", "2024-01-01"); + expect(input).toHaveAttribute("max", "2024-12-31"); + }); }); diff --git a/frontend/src/ts/components/pages/settings/custom-setting/CustomBackground.tsx b/frontend/src/ts/components/pages/settings/custom-setting/CustomBackground.tsx index 78615c898719..fbbcf8897d0d 100644 --- a/frontend/src/ts/components/pages/settings/custom-setting/CustomBackground.tsx +++ b/frontend/src/ts/components/pages/settings/custom-setting/CustomBackground.tsx @@ -142,12 +142,7 @@ export function CustomBackground(): JSXElement { { - const val = value; - return fromSchema(CustomBackgroundSchema)({ - value: val, - }); - }, + onChange: fromSchema(CustomBackgroundSchema), onBlur: () => { void form.handleSubmit(); }, diff --git a/frontend/src/ts/components/ui/form/InputField.tsx b/frontend/src/ts/components/ui/form/InputField.tsx index 75074d3b5071..88f7a296287c 100644 --- a/frontend/src/ts/components/ui/form/InputField.tsx +++ b/frontend/src/ts/components/ui/form/InputField.tsx @@ -174,7 +174,7 @@ function convertStringToValue( // oxlint-disable-next-line typescript/no-unsafe-member-access field.form.options.defaultValues?.[field.name]; if (defaultValue === undefined || defaultValue === null) return newValue as T; - if (newValue === "") return undefined; + if (newValue === "" && typeof defaultValue !== "string") return undefined; if (typeof defaultValue === "number") return Number.parseFloat(newValue) as T; return newValue as T;