From 27fe15976fb273bf83792299a1a1803a6f35f168 Mon Sep 17 00:00:00 2001 From: cliffhall Date: Sun, 16 Aug 2026 01:00:48 -0400 Subject: [PATCH] fix(web): admit null in the number field's value and default prop types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Copilot review: a nullable number schema really does produce `null` for both the raw value and the schema default, but the props declared only `number | undefined` and the call site cast the null away. The runtime already handled it — the initializer's `?? ""` exists for exactly that — so the types were the part that was wrong, and a cast hiding it is how a future null bug goes unseen by the compiler. Widen both to `number | null | undefined` and drop the narrowing casts, keeping the distinction the initializer encodes: `undefined` takes the default, `null` is a value and renders as an empty box. Signed-off-by: cliffhall --- .../groups/SchemaForm/SchemaForm.tsx | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/clients/web/src/components/groups/SchemaForm/SchemaForm.tsx b/clients/web/src/components/groups/SchemaForm/SchemaForm.tsx index acd59ca7..46103ba0 100644 --- a/clients/web/src/components/groups/SchemaForm/SchemaForm.tsx +++ b/clients/web/src/components/groups/SchemaForm/SchemaForm.tsx @@ -337,10 +337,17 @@ interface SchemaNumberInputProps { description?: string; withAsterisk: boolean; disabled: boolean; - /** Raw, not `resolveValue`-substituted — see `SchemaJsonFieldProps.value`. */ - value: number | undefined; - /** The schema `default`, used to seed the draft only (#2026). */ - defaultValue: number | undefined; + /** + * 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. + */ + value: number | null | undefined; + /** The schema `default`, used to seed the draft only (#2026). May be `null`. */ + defaultValue: number | null | undefined; min?: number; max?: number; allowDecimal: boolean; @@ -627,9 +634,12 @@ export function SchemaForm({ description={description} withAsterisk={isRequired} disabled={disabled} - // Raw and default kept apart, not pre-resolved (#2026). - value={values[fieldName] as number | undefined} - defaultValue={getDefaultValue(fieldSchema) as number | undefined} + // Raw and default kept apart, not pre-resolved (#2026). Both admit + // `null`, which a nullable number schema really produces. + value={values[fieldName] as number | null | undefined} + defaultValue={ + getDefaultValue(fieldSchema) as number | null | undefined + } min={fieldSchema.minimum} max={fieldSchema.maximum} // An `integer` field rejects the decimal point outright rather than