From 8926290c58c0fd25b1f39ae613ca7775eadaa137 Mon Sep 17 00:00:00 2001 From: Danny Rorabaugh Date: Mon, 27 Jul 2026 16:15:11 -0400 Subject: [PATCH] Adopt RadioGroup for the WipeModal scope selector (Tier 2) Replace the hand-rolled two-radio group in WipeModal with platform RadioGroup/RadioGroupItem + Label, preserving the wipe-scope-book / wipe-scope-all test ids, the disabled-when-no-book rule, and the scope descriptions. Extend the platform-bible-react jest mock with RadioGroup/RadioGroupItem stubs. The Tier 2 content-sized gloss inputs are intentionally left raw; see the PR description for the verification that platform Input's injected form-field styling can't preserve their field-sizing/compact layout. Co-Authored-By: Claude Opus 4.8 (1M context) --- __mocks__/platform-bible-react.tsx | 94 ++++++++++++++++++++++++++++- src/components/modals/WipeModal.tsx | 52 ++++++++-------- 2 files changed, 119 insertions(+), 27 deletions(-) diff --git a/__mocks__/platform-bible-react.tsx b/__mocks__/platform-bible-react.tsx index 0966e894..a14d7e7c 100644 --- a/__mocks__/platform-bible-react.tsx +++ b/__mocks__/platform-bible-react.tsx @@ -3,7 +3,17 @@ * without extra transform configuration. This stub provides the subset used by the extension. */ -import { Children, cloneElement, forwardRef, isValidElement, useEffect, useRef } from 'react'; +import { + Children, + cloneElement, + createContext, + forwardRef, + isValidElement, + useContext, + useEffect, + useMemo, + useRef, +} from 'react'; import type { ChangeEventHandler, CSSProperties, @@ -576,6 +586,88 @@ export function Switch({ ); } +/** + * Context carrying the {@link RadioGroup}'s selected value and change handler down to each + * {@link RadioGroupItem}, mirroring how the real Radix-based component coordinates its items. + */ +const RadioGroupContext = createContext<{ + onValueChange?: (value: string) => void; + value?: string; +}>({}); + +/** + * Stub radio group rendered as a `
` that shares its selected value and change + * handler with its {@link RadioGroupItem} children via context. The real component is built on Radix + * primitives; this stub reproduces just the controlled selection behavior tests drive. + * + * @param props - Component props. + * @param props.children - The {@link RadioGroupItem}s (and any surrounding markup). + * @param props.className - CSS class names. + * @param props.onValueChange - Called with an item's value when it becomes selected. + * @param props.value - Currently selected item value. + * @returns A `
` providing selection context to its items. + */ +export function RadioGroup({ + children, + className, + onValueChange, + value, +}: Readonly<{ + children?: ReactNode; + className?: string; + onValueChange?: (value: string) => void; + value?: string; +}>): ReactElement { + const contextValue = useMemo(() => ({ onValueChange, value }), [onValueChange, value]); + return ( +
+ {children} +
+ ); +} + +/** + * Stub radio item rendered as a native `` so `toBeChecked`, `toBeDisabled`, and + * click/`check` interactions work in tests. It reads the enclosing {@link RadioGroup}'s value from + * context, marking itself checked when they match and reporting its own value on change. (The real + * component renders a `