From d048d72df2cda2e1148f306611c7e7287d0d55ae Mon Sep 17 00:00:00 2001 From: AneoPsy Date: Mon, 2 Mar 2026 23:54:24 -1000 Subject: [PATCH] Fix AMS slot modal infinite scroll loop on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inline callback refs on preset buttons called scrollIntoView on every re-render, creating a scroll → re-render → scrollIntoView loop on Windows. Replace with a useEffect + data attribute approach that only scrolls when the selected preset actually changes. --- .../src/components/ConfigureAmsSlotModal.tsx | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/ConfigureAmsSlotModal.tsx b/frontend/src/components/ConfigureAmsSlotModal.tsx index 0e83d4dbc..2136fe40c 100644 --- a/frontend/src/components/ConfigureAmsSlotModal.tsx +++ b/frontend/src/components/ConfigureAmsSlotModal.tsx @@ -1,4 +1,4 @@ -import { useState, useMemo, useEffect, useCallback } from 'react'; +import { useState, useMemo, useEffect, useCallback, useRef } from 'react'; import { useQuery, useMutation } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { X, Loader2, Settings2, ChevronDown, CheckCircle2, RotateCcw } from 'lucide-react'; @@ -242,6 +242,7 @@ export function ConfigureAmsSlotModal({ const [searchQuery, setSearchQuery] = useState(''); const [showSuccess, setShowSuccess] = useState(false); const [showExtendedColors, setShowExtendedColors] = useState(false); + const scrolledToRef = useRef(''); // Fetch cloud settings (gracefully handle 401 when logged out) const { data: cloudSettings, isLoading: settingsLoading, isError: cloudError } = useQuery({ @@ -735,6 +736,7 @@ export function ConfigureAmsSlotModal({ setColorInput(''); setSearchQuery(''); setShowSuccess(false); + scrolledToRef.current = ''; } }, [isOpen, slotInfo.savedPresetId, slotInfo.trayInfoIdx, slotInfo.trayColor, cloudSettings?.filament]); @@ -770,6 +772,17 @@ export function ConfigureAmsSlotModal({ } }, [isOpen, handleKeyDown]); + // Scroll selected preset into view only when the selection changes (not on every render). + // Inline callback refs cause scrollIntoView to fire every render, which on Windows + // creates an infinite scroll loop due to scroll → re-render → scrollIntoView cycles. + useEffect(() => { + if (selectedPresetId && selectedPresetId !== scrolledToRef.current) { + scrolledToRef.current = selectedPresetId; + const el = document.querySelector(`[data-preset-id="${CSS.escape(selectedPresetId)}"]`); + el?.scrollIntoView({ block: 'nearest' }); + } + }, [selectedPresetId]); + if (!isOpen) return null; const isLoading = (settingsLoading && !cloudError) || localLoading || builtinLoading || kprofilesLoading; @@ -889,9 +902,7 @@ export function ConfigureAmsSlotModal({ filteredPresets.map((preset) => (