From 970a9baec314370cefd31886c5ea15df02644fb5 Mon Sep 17 00:00:00 2001 From: nns <278048682+nurdotnet@users.noreply.github.com> Date: Sun, 26 Apr 2026 02:42:24 +0500 Subject: [PATCH] fix(supply-quick-add): sticky input at viewport bottom + auto-scroll on add MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Quick-add bar теперь не sticky-внутри-Section, а отдельный flex-sibling формы — всегда прибит к нижнему краю viewport независимо от высоты содержимого и overflow-hidden у Section'а:
← скроллится ← всегда виден После каждого добавления строки скролл-контейнер тела документа автоскроллится к низу (smooth, через requestAnimationFrame чтобы дождаться рендера новой строки) — новая строка всегда появляется прямо над input'ом и пользователь видит подтверждение скана. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../src/pages/SupplyEditPage.tsx | 46 ++++++++++++------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/src/food-market.web/src/pages/SupplyEditPage.tsx b/src/food-market.web/src/pages/SupplyEditPage.tsx index 191fc16..caba533 100644 --- a/src/food-market.web/src/pages/SupplyEditPage.tsx +++ b/src/food-market.web/src/pages/SupplyEditPage.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect, type FormEvent, type ReactNode } from 'react' +import { useState, useEffect, useRef, type FormEvent, type ReactNode } from 'react' import { useNavigate, useParams, Link } from 'react-router-dom' import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query' import { ArrowLeft, Plus, Trash2, Save, CheckCircle } from 'lucide-react' @@ -65,6 +65,16 @@ export function SupplyEditPage() { const [form, setForm] = useState
(emptyForm) const [pickerOpen, setPickerOpen] = useState(false) const [error, setError] = useState(null) + // Скролл-контейнер тела документа: после каждого добавления строки + // автоскроллим к низу, чтобы новая строка и input оказались в зоне видимости. + const scrollBodyRef = useRef(null) + const scrollToBottom = () => { + const el = scrollBodyRef.current + if (!el) return + requestAnimationFrame(() => { + el.scrollTo({ top: el.scrollHeight, behavior: 'smooth' }) + }) + } const existing = useQuery({ queryKey: ['/api/purchases/supplies', id], @@ -211,6 +221,7 @@ export function SupplyEditPage() { ...form, lines: form.lines.map((l, ix) => ix === idx ? { ...l, quantity: l.quantity + 1 } : l), }) + scrollToBottom() return true } const defaultRetail = p.prices?.[0]?.amount ?? null @@ -228,6 +239,7 @@ export function SupplyEditPage() { retailPriceOverride: null, }], }) + scrollToBottom() return false } const updateLine = (i: number, patch: Partial) => @@ -273,7 +285,7 @@ export function SupplyEditPage() { {/* Scrollable body */} -
+
{error && (
{error}
@@ -448,23 +460,25 @@ export function SupplyEditPage() { )} - - {!isPosted && ( - // Sticky-bottom вне Section (overflow-hidden родителя ломает sticky): - // пользователь может подряд сканировать партию штрихкодов — после - // каждого скана строка добавляется в таблицу выше, а input остаётся - // прибит к низу скроллируемого тела документа и принимает следующий ввод. -
- -
- )}
+ {/* Quick-add bar — flex-sibling формы, всегда у нижнего края viewport. + * Не sticky внутри scroll-body, чтобы overflow родителей и высота + * содержимого не влияли на видимость. После каждого добавления + * строки тело документа автоскроллится к низу. */} + {!isPosted && ( +
+
+ +
+
+ )} + setPickerOpen(false)} onPick={addLineFromProduct} /> )