From a945fb71c6e44f3101de602317c884ebde3de82d Mon Sep 17 00:00:00 2001 From: cliffhall Date: Sun, 16 Aug 2026 01:08:40 -0400 Subject: [PATCH] docs: correct how a null reaches the number field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Copilot review: the comments offered "a nullable number the user cleared" as a way to get an explicit `null` into this field. Clearing the box reports `undefined` — `toNumericValue("")` says so, and an existing test pins it — so the only way `null` arrives is from parent state: a value received from the server, restored from a deep link, or written by a caller for a nullable schema. Say that in all three places instead. Signed-off-by: cliffhall --- .../groups/SchemaForm/SchemaForm.test.tsx | 7 +++++-- .../groups/SchemaForm/SchemaForm.tsx | 19 ++++++++++++------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/clients/web/src/components/groups/SchemaForm/SchemaForm.test.tsx b/clients/web/src/components/groups/SchemaForm/SchemaForm.test.tsx index 3c7193df..b1d3182f 100644 --- a/clients/web/src/components/groups/SchemaForm/SchemaForm.test.tsx +++ b/clients/web/src/components/groups/SchemaForm/SchemaForm.test.tsx @@ -1743,8 +1743,11 @@ describe("SchemaForm defaulted fields (#2026)", () => { }); // An explicit `null` is a value, not an absent one, so a non-null default - // must not be substituted for it. Reachable for a nullable number field the - // user cleared, or one the server sent as null. + // must not be substituted for it. Note the field itself never emits `null` — + // clearing it reports `undefined` (pinned by "passes undefined to onChange + // when a number field is cleared") — so this arrives from parent state: a + // value received from the server, restored from a deep link, or written by a + // caller for a nullable schema. it("shows an explicit null as empty, not as the default", () => { const schema: InspectorFormSchema = { type: "object", diff --git a/clients/web/src/components/groups/SchemaForm/SchemaForm.tsx b/clients/web/src/components/groups/SchemaForm/SchemaForm.tsx index 46103ba0..152fe40f 100644 --- a/clients/web/src/components/groups/SchemaForm/SchemaForm.tsx +++ b/clients/web/src/components/groups/SchemaForm/SchemaForm.tsx @@ -341,9 +341,9 @@ interface SchemaNumberInputProps { * Raw, not `resolveValue`-substituted — see `SchemaJsonFieldProps.value`. * * `null` is admitted alongside `undefined` because a nullable number schema - * produces it, and the two are not interchangeable here: `undefined` means - * "no value supplied" and takes `defaultValue`, while `null` is a value and - * displays as an empty box. + * produces it — by way of parent state, never by clearing the box — and the + * two are not interchangeable here: `undefined` means "no value supplied" + * and takes `defaultValue`, while `null` is a value and displays empty. */ value: number | null | undefined; /** The schema `default`, used to seed the draft only (#2026). May be `null`. */ @@ -387,10 +387,15 @@ function SchemaNumberInput({ ...inputProps }: SchemaNumberInputProps) { // `undefined` means "no value supplied", which is what the default is for. - // An explicit `null` is a value — a nullable number the user cleared, or one - // the server sent — so it must not be overwritten by a non-null default; it - // displays as the empty box `resolveValue` produced before. Hence the - // `undefined` test rather than `??`, matching `SchemaJsonField`. + // An explicit `null` is a value, so it must not be overwritten by a non-null + // default; it displays as the empty box `resolveValue` produced before. + // Hence the `undefined` test rather than `??`, matching `SchemaJsonField`. + // + // Clearing the box does *not* produce that `null` — `toNumericValue("")` + // reports `undefined`, which is the behavior the "passes undefined to + // onChange when a number field is cleared" test pins. A `null` reaches this + // field only from parent state: a value received from the server, restored + // from a deep link, or written by a caller for a nullable schema. const [draft, setDraft] = useState( (value === undefined ? defaultValue : value) ?? "", );