From 63e37dd0bb2f80404ca02b0feeacd0c1d3a70238 Mon Sep 17 00:00:00 2001 From: Codex Review Integration Date: Tue, 18 Aug 2026 14:27:42 -0300 Subject: [PATCH] fix(vendors): keep trades live region out of Stack spacing (SH-249) The always-mounted aria-live feedback region inherited MUI Stack spacing, adding a permanent gap under the trades input and shifting the approved Vendor edit drawer layout. vendor-visual-regression caught it. Move the region outside the spaced Stack and collapse it while silent, so the live region stays in the DOM for announcements without claiming layout. Restores the caption to MUI Typography; that swap was cosmetic and out of scope for SH-249. --- .../vendor-trade-specialties-field.tsx | 58 ++++++++++++++++--- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/src/app/(protected)/vendors/_components/vendor-trade-specialties-field.tsx b/src/app/(protected)/vendors/_components/vendor-trade-specialties-field.tsx index 90329e41..490f554d 100644 --- a/src/app/(protected)/vendors/_components/vendor-trade-specialties-field.tsx +++ b/src/app/(protected)/vendors/_components/vendor-trade-specialties-field.tsx @@ -4,10 +4,53 @@ import AddIcon from "@mui/icons-material/Add"; import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward"; import ArrowUpwardIcon from "@mui/icons-material/ArrowUpward"; import CloseIcon from "@mui/icons-material/Close"; -import { Autocomplete, Box, Button, Chip, FormLabel, Stack, TextField } from "@mui/material"; +import { + Autocomplete, + Box, + Button, + Chip, + FormLabel, + Stack, + TextField, + Typography, +} from "@mui/material"; import { Text } from "@/components/ui/text"; import type { VendorCompanyRosterFormValues } from "@/domain/vendors/schemas/vendor-roster-schema"; +/** + * `Text variant="feedback"` stays mounted when silent so the aria-live region can announce later. + * An empty paragraph still claims a line box, which would add a permanent gap under the trades + * input and shift the approved drawer layout. Collapse the box while keeping the node in the DOM + * (never `display: none`, which would stop announcements). + */ +function collapsedWhenSilent(visible: boolean) { + return visible ? undefined : { height: 0, margin: 0, overflow: "hidden" as const }; +} + +function TradeFeedbackRegions({ + listUnavailable, + message, +}: { + listUnavailable: boolean; + message: string | null; +}) { + return ( + <> + + Trade list is unavailable right now — you can still type a trade manually. + + + {message} + + + ); +} + function splitTrades(value: string | undefined): string[] { return (value ?? "") .split(",") @@ -52,9 +95,9 @@ export function VendorTradeSpecialtiesField({ return ( Trade Specialties - + First trade is primary. Reorder with the arrows. - + - - Trade list is unavailable right now — you can still type a trade manually. - - - {feedbackMessage} - {trades.length > 1 && ( {trades.map((trade, tradeIndex) => ( @@ -186,6 +223,9 @@ export function VendorTradeSpecialtiesField({ ); }} /> + {/* Outside the spaced Stack: an always-mounted live region would otherwise inherit Stack + spacing and add a permanent gap under the trades input, shifting the approved layout. */} + ); }