Gogs e3d664bdc9 -- пре 3 недеља
..
README.md e3d664bdc9 -- пре 3 недеља
index.coffee 80710f8924 -- пре 3 недеља
index.pug 0d65f80d29 -- пре 3 недеља
index.styl 06219819b6 -- пре 3 недеља

README.md

Компонент ModalWindow - Полная документация

Назначение компонента

ModalWindow - универсальный компонент для создания модальных окон (диалоговых окон) в приложении. Предоставляет функциональность для отображения контента поверх основного интерфейса с затемнением фона, анимациями и управлением через глобальную шину событий.

git репозитарий

https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/src/master/vue/app/shared/ModalWindow/

Архитектура компонента

Структура файлов

app/shared/ModalWindow/
├── index.coffee    # Логика компонента
├── index.pug       # Шаблон
└── index.styl      # Стили

Импорт и регистрация

# В основном файле приложения (app/temp.coffee)
components:
    'modal-window': require 'app/shared/ModalWindow'

Базовое использование

1. Простое модальное окно

modal-window(
    :is-visible="showModal"
    @close="showModal = false"
)
    template([body])
        h2(class="text-xl font-bold mb-4") Заголовок
        p Содержимое модального окна

2. С кнопками действий

modal-window(
    :is-visible="showModal"
    @close="showModal = false"
    @confirm="handleConfirm"
)
    template([body])
        h2(class="text-xl font-bold mb-4") Подтверждение
        p Вы уверены, что хотите выполнить это действие?
    
    template([footer])
        button(@click="$emit('close')" class="btn-secondary") Отмена
        button(@click="$emit('confirm')" class="btn-primary") Подтвердить

Полный список props

isVisible (обязательный)

  • Тип: Boolean
  • Описание: Управляет видимостью модального окна
  • Пример:

    modal-window(:is-visible="isModalOpen")
    

title (опциональный)

  • Тип: String
  • По умолчанию: ''
  • Описание: Заголовок модального окна
  • Пример:

    modal-window(:is-visible="showModal" title="Заголовок окна")
    

size (опциональный)

  • Тип: String
  • По умолчанию: 'md'
  • Допустимые значения: 'sm', 'md', 'lg', 'xl', 'full'
  • Описание: Размер модального окна
  • Пример:

    modal-window(:is-visible="showModal" size="lg")
    

closeOnBackdrop (опциональный)

  • Тип: Boolean
  • По умолчанию: true
  • Описание: Закрывать ли окно при клике на подложку
  • Пример:

    modal-window(:is-visible="showModal" :close-on-backdrop="false")
    

closeOnEscape (опциональный)

  • Тип: Boolean
  • По умолчанию: true
  • Описание: Закрывать ли окно при нажатии Escape
  • Пример:

    modal-window(:is-visible="showModal" :close-on-escape="false")
    

showCloseButton (опциональный)

  • Тип: Boolean
  • По умолчанию: true
  • Описание: Показывать ли кнопку закрытия
  • Пример:

    modal-window(:is-visible="showModal" :show-close-button="false")
    

overlayClass (опциональный)

  • Тип: String
  • По умолчанию: ''
  • Описание: Дополнительные классы для подложки
  • Пример:

    modal-window(:is-visible="showModal" overlay-class="bg-opacity-80")
    

contentClass (опциональный)

  • Тип: String
  • По умолчанию: ''
  • Описание: Дополнительные классы для контента
  • Пример:

    modal-window(:is-visible="showModal" content-class="custom-modal-style")
    

События (Events)

@close

  • Описание: Событие закрытия модального окна
  • Payload: null
  • Пример:

    modal-window(:is-visible="showModal" @close="handleModalClose")
    

@confirm (опциональный)

  • Описание: Событие подтверждения действия
  • Payload: null
  • Пример:

    modal-window(:is-visible="showModal" @confirm="handleConfirm")
    

@opened

  • Описание: Событие полного открытия модального окна (после анимации)
  • Payload: null
  • Пример:

    modal-window(:is-visible="showModal" @opened="handleModalOpened")
    

@closed

  • Описание: Событие полного закрытия модального окна (после анимации)
  • Payload: null
  • Пример:

    modal-window(:is-visible="showModal" @closed="handleModalClosed")
    

Слоты (Slots)

[body] (основной слот)

  • Описание: Основное содержимое модального окна
  • Пример:

    modal-window(:is-visible="showModal")
      template([body])
          h2 Заголовок
          p Основной контент
          form
              input(type="text" placeholder="Введите данные")
              button(type="submit") Отправить
    

[header] (опциональный)

  • Описание: Заголовочная область модального окна
  • Пример:

    modal-window(:is-visible="showModal")
      template([header])
          div(class="flex items-center justify-between")
              h2(class="text-xl font-bold") Пользовательский заголовок
              custom-close-button(@click="$emit('close')")
      
      template([body])
          p Содержимое модального окна
    

[footer] (опциональный)

  • Описание: Нижняя область модального окна (обычно для кнопок)
  • Пример:

    modal-window(:is-visible="showModal")
      template([body])
          p Вы уверены, что хотите удалить этот элемент?
      
      template([footer])
          div(class="flex justify-end space-x-3")
              button(@click="$emit('close')" class="btn-secondary") Отмена
              button(@click="$emit('confirm')" class="btn-danger") Удалить
    

Размеры модальных окон

Доступные размеры

//- Маленькое (sm)
modal-window(:is-visible="showModal" size="sm")

//- Среднее (md) - по умолчанию
modal-window(:is-visible="showModal" size="md")

//- Большое (lg)
modal-window(:is-visible="showModal" size="lg")

//- Очень большое (xl)
modal-window(:is-visible="showModal" size="xl")

//- На весь экран (full)
modal-window(:is-visible="showModal" size="full")

Стили и CSS классы

Базовые классы

  • .modal-overlay - класс подложки
  • .modal-container - класс контейнера
  • .modal-content - класс контента

Модификаторы размера

  • .modal--sm - маленький размер
  • .modal--md - средний размер (по умолчанию)
  • .modal--lg - большой размер
  • .modal--xl - очень большой размер
  • .modal--full - на весь экран

Состояния анимации

  • .modal-enter-active - анимация появления
  • .modal-leave-active - анимация исчезновения

Примеры использования в различных сценариях

1. Простая информационная модалка

modal-window(
    :is-visible="showInfoModal"
    @close="showInfoModal = false"
    title="Информация"
)
    template([body])
        p(class="mb-4") Это информационное модальное окно с простым текстом.
        p Вы можете закрыть его, нажав на крестик или кликнув вне окна.

2. Модалка подтверждения действия

modal-window(
    :is-visible="showConfirmModal"
    @close="showConfirmModal = false"
    @confirm="handleDeleteConfirm"
    title="Подтверждение удаления"
    size="sm"
)
    template([body])
        p Вы уверены, что хотите удалить "{{ itemName }}"? Это действие нельзя отменить.

    template([footer])
        div(class="flex justify-end space-x-3")
            button(
                @click="$emit('close')"
                class="px-4 py-2 text-gray-600 hover:text-gray-800 transition-colors"
            ) Отмена
            button(
                @click="$emit('confirm')"
                class="px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700 transition-colors"
            ) Удалить

3. Форма в модальном окне

modal-window(
    :is-visible="showFormModal"
    @close="closeFormModal"
    title="Добавить мероприятие"
    size="lg"
    :close-on-backdrop="false"
)
    template([body])
        form(@submit.prevent="submitEventForm")
            div(class="space-y-4")
                div
                    label(for="title" class="block text-sm font-medium text-gray-700") Название
                    input(
                        id="title"
                        v-model="form.title"
                        type="text"
                        class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
                        required
                    )
                
                div
                    label(for="description" class="block text-sm font-medium text-gray-700") Описание
                    textarea(
                        id="description"
                        v-model="form.description"
                        rows="4"
                        class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
                    )
    
    template([footer])
        div(class="flex justify-end space-x-3")
            button(
                type="button"
                @click="$emit('close')"
                class="px-4 py-2 text-gray-600 hover:text-gray-800 transition-colors"
            ) Отмена
            button(
                type="submit"
                class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors"
            ) Сохранить

4. Модалка с кастомным заголовком

modal-window(
    :is-visible="showCustomModal"
    @close="showCustomModal = false"
    :show-close-button="false"
)
    template([header])
        div(class="bg-gradient-to-r from-blue-500 to-purple-600 text-white p-6")
            div(class="flex items-center justify-between")
                div
                    h2(class="text-2xl font-bold") Премиум функции
                    p(class="text-blue-100") Доступно только для премиум пользователей
                button(
                    @click="$emit('close')"
                    class="text-white hover:text-blue-200 transition-colors"
                )
                    icon(name="close" class="w-6 h-6")
    
    template([body])
        div(class="p-6")
            ul(class="space-y-3")
                li(class="flex items-center")
                    icon(name="check" class="w-5 h-5 text-green-500 mr-3")
                    span Расширенная аналитика
                li(class="flex items-center")
                    icon(name="check" class="w-5 h-5 text-green-500 mr-3")
                    span Приоритетная поддержка
                li(class="flex items-center")
                    icon(name="check" class="w-5 h-5 text-green-500 mr-3")
                    span Кастомные домены
    
    template([footer])
        div(class="bg-gray-50 px-6 py-4 flex justify-between items-center")
            span(class="text-gray-600") Всего 999 TJS/месяц
            button(
                @click="subscribePremium"
                class="px-6 py-2 bg-gradient-to-r from-blue-500 to-purple-600 text-white rounded-lg hover:from-blue-600 hover:to-purple-700 transition-colors"
            ) Подписаться

5. Модалка с загрузкой контента

modal-window(
    :is-visible="showLoadingModal"
    @close="cancelLoading"
    title="Загрузка"
    :close-on-escape="false"
    :close-on-backdrop="false"
    :show-close-button="false"
)
    template([body])
        div(class="text-center py-8")
            div(class="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4")
            p Загрузка данных, пожалуйста подождите...

6. Модалка с вкладками

modal-window(
    :is-visible="showTabsModal"
    @close="showTabsModal = false"
    title="Настройки"
    size="lg"
)
    template([body])
        div
            div(class="border-b border-gray-200")
                nav(class="-mb-px flex space-x-8")
                    button(
                        v-for="tab in tabs"
                        :key="tab.id"
                        @click="currentTab = tab.id"
                        :class="{
                            'border-blue-500 text-blue-600': currentTab === tab.id,
                            'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300': currentTab !== tab.id
                        }"
                        class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm"
                    ) {{ tab.name }}
            
            div(class="py-4")
                div(v-if="currentTab === 'general'")
                    h3(class="text-lg font-medium mb-4") Основные настройки
                    //- Контент вкладки
                
                div(v-else-if="currentTab === 'security'")
                    h3(class="text-lg font-medium mb-4") Безопасность
                    //- Контент вкладки

Управление через глобальную шину событий

Открытие модального окна

# В любом компоненте
EventBus.emit('open_modal', {
    component: require('app/components/CustomModal'),
    props: {
        title: 'Кастомное окно',
        data: someData
    }
})

Закрытие модального окна

# Закрытие текущего модального окна
EventBus.emit('close_modal')

# Закрытие всех модальных окон
EventBus.emit('close_all_modals')

Интеграция с глобальным состоянием

Использование с appState

# В основном приложении
appState:
    modalState:
        isVisible: false
        component: null
        props: {}

# Открытие модалки
openModal: (component, props = {}) ->
    @appState.modalState.component = component
    @appState.modalState.props = props
    @appState.modalState.isVisible = true

# В шаблоне
modal-window(
    :is-visible="appState.modalState.isVisible"
    @close="closeModal"
    v-if="appState.modalState.component"
)
    component(
        :is="appState.modalState.component"
        v-bind="appState.modalState.props"
        @close="closeModal"
    )

Анимации и переходы

Кастомные анимации

// В стилях компонента
.modal-custom-enter-active
    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1)
    
    .modal-container
        transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1)
        transform: scale(0.95) translateY(-10px)
        opacity: 0

.modal-custom-enter-to
    .modal-container
        transform: scale(1) translateY(0)
        opacity: 1

Best Practices

1. Управление состоянием

# Правильно - реактивное управление
data: ->
    return
        showModal: false

methods:
    openModal: ->
        @showModal = true
    
    closeModal: ->
        @showModal = false

2. Обработка подтверждений

methods:
    handleConfirm: ->
        try
            await this.performAction()
            this.showModal = false
            this.showSuccessMessage()
        catch error
            this.showErrorMessage(error)

3. Доступность

//- Добавляйте aria-атрибуты для доступности
modal-window(
    :is-visible="showModal"
    @close="closeModal"
    role="dialog"
    aria-labelledby="modal-title"
)
    template([header])
        h2(id="modal-title") Заголовок модалки

4. Управление фокусом

# Автоматически фокусироваться на первом интерактивном элементе
mounted: ->
    this.$nextTick(() ->
        const firstInput = this.$el.querySelector('input, button, textarea')
        if firstInput
            firstInput.focus()
    )

Отладка и разработка

Логирование событий

# Отслеживание событий модального окна
EventBus.on('modal_opened', (data) ->
    debug.log "Модальное окно открыто: "+data.component?.name
)

EventBus.on('modal_closed', (data) ->
    debug.log "Модальное окно закрыто"
)

Проверка доступности

# Проверка управления фокусом
checkFocusManagement: ->
    if this.isVisible
        const activeElement = document.activeElement
        const modalContent = this.$el.querySelector('.modal-content')
        
        if modalContent and !modalContent.contains(activeElement)
            debug.log "Фокус вне модального окна!"

Компонент ModalWindow предоставляет мощный и гибкий инструмент для создания модальных окон с поддержкой анимаций, управления через события, кастомизацией и соблюдением лучших практик доступности.