From abf63328554545636375dfd34f9e0b258154fc81 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 30 Aug 2026 11:28:39 +0000 Subject: [PATCH] fix(forms): keep native password input for format:password; drop dead forwardRef --- frontend/src/forms/SchemaForm.test.tsx | 21 +++++++++++++ frontend/src/forms/SchemaForm.tsx | 41 ++++++++++++++++---------- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/frontend/src/forms/SchemaForm.test.tsx b/frontend/src/forms/SchemaForm.test.tsx index acac116..bc5aa50 100644 --- a/frontend/src/forms/SchemaForm.test.tsx +++ b/frontend/src/forms/SchemaForm.test.tsx @@ -87,4 +87,25 @@ describe("SchemaForm — ExpressionField-backed", () => { expect(screen.getByText("URL")).toBeInTheDocument(); expect(screen.getByText("*")).toBeInTheDocument(); }); + + it("format:password fields render as a native password input, not an expression field", () => { + const schema: JsonSchemaObject = { + type: "object", + properties: { + pass: { type: "string", format: "password", title: "Password" }, + }, + }; + render( + {}} + previewInput={{ anything: "goes" }} + />, + ); + const el = screen.getByLabelText(/password/i); + expect(el).toHaveAttribute("type", "password"); + // No expression preview leaked even though previewInput was provided. + expect(screen.queryByTestId("expr-preview")).not.toBeInTheDocument(); + }); }); diff --git a/frontend/src/forms/SchemaForm.tsx b/frontend/src/forms/SchemaForm.tsx index 7828c12..1abd443 100644 --- a/frontend/src/forms/SchemaForm.tsx +++ b/frontend/src/forms/SchemaForm.tsx @@ -1,4 +1,4 @@ -import { forwardRef, useImperativeHandle, useRef } from "react"; +import { useRef } from "react"; import type { JsonSchemaObject } from "@/api/types"; import { ExpressionField, @@ -29,23 +29,33 @@ export function SchemaForm({ schema, value, onChange, previewInput, onFieldFocus const id = `sf-${name}`; const isRequired = required.has(name); const raw = toEditorString(value[name]); - const st = mapSchemaType(prop.type); + const isSecret = prop.format === "password"; return ( ); })} @@ -53,14 +63,13 @@ export function SchemaForm({ schema, value, onChange, previewInput, onFieldFocus ); } -const SchemaExpressionField = forwardRef void; previewInput?: unknown; schemaType?: ExpressionSchemaType; singleLine?: boolean; codeBlock?: boolean; onFieldFocus?: (handle: ExpressionFieldHandle) => void; -}>(function SchemaExpressionField(props, _outer) { +}) { const ref = useRef(null); - useImperativeHandle(_outer, () => ref.current ?? { insertAtCaret: () => {}, focus: () => {} }); return ( { if (ref.current) props.onFieldFocus?.(ref.current); }} /> ); -}); +} function mapSchemaType(t?: string): ExpressionSchemaType { if (t === "integer") return "integer";