decision-modal-component-extraction.md 3.4 KB

Decision: Извлечение компонента Modal

Контекст: В проекте 7 мест с ad-hoc модалками и проблема со скроллбаром на оверлее. Нужно было выбрать между починкой на месте и извлечением переиспользуемого компонента.

Альтернативы

Подход Плюсы Минусы
Исправить на месте (добавить max-h-[90vh] overflow-y-auto в каждую) Минимум изменений, нет нового кода Нарушает DRY, будущие модалки снова ad-hoc, сложнее поддерживать единообразие
Извлечь компонент Modal (выбрано) DRY, единый источник стилей, новые модалки сразу правильные, упрощает рефакторинг +1 файл, need migration 7 мест
Headless UI / Radix Dialog a11y из коробки, portal, focus trap Зависимость, переписывание всех стилей, избыточно для текущего масштаба

Выбор

Извлечение компонента Modal. Почему:

  1. DRY: 7 копий одинакового оверлея + stopPropagation — явный код-смэлл
  2. Единый источник истины: скроллбар теперь всегда внутри контента (max-h-[90vh] overflow-y-auto на inner div)
  3. Расширяемость: новые размеры (sm/md/lg/xl), className override для кастомного фона
  4. Простота: без зависимостей, чистый Tailwind
  5. Будущие модалки: больше не будут дублировать разметку

Компромиссы

  • Не добавили portal / focus trap / escape-key (a11y) — оставлено на будущее
  • Не использовали готовую библиотеку (Headless UI/Radix) — не переусложняем

Реализация

Файл: frontend/src/components/Modal.tsx

// Ключевая строка — скроллбар внутри контента
className={`w-full ${sizeClasses[size]} max-h-[90vh] overflow-y-auto ... ${className}`}

Результат

graph TD
    A[7 ad-hoc модалок<br/>разный scroll/no-scroll] --> B[1 компонент Modal]
    B --> C[Скроллбар внутри модалки]
    B --> D[Единый стиль]
    B --> E[Будущие модалки = 1 строчка]
  • Удалено: ~30 строк дублированной разметки (по 4-5 строк на каждую модалку)
  • Добавлено: 1 компонент, 40 строк
  • Чистый профит: +10 строк, но DRY и гарантированный скроллбар

Связанные заметки

  • [[atomic-modal-scrollbar-inside]] — детали рефакторинга
  • [[architecture-overview]]
  • [[frontend-api-client]]

Источник

Задача 2026-07-04: «Если в модалке нужен скроллбар, то он должен быть внутри модалки».

Теги

#decision #frontend #react #modal #DRY #refactoring