import {Meta} from '@storybook/addon-docs/blocks'

<Meta title='@dxtmisha/ru/functional/Classes/EventRef - Реактивный менеджер событий'/>

# Класс EventRef

Реактивный менеджер событий, упрощающий управление слушателями для DOM-элементов или объекта `window`. Автоматически обновляет подписки при изменении целевого элемента (переданного как Vue `Ref`).

Включает автоматическую обработку перепривязки слушателей при динамическом изменении элементов и интеграцию с жизненным циклом Vue.

## Ключевые особенности

- **Реактивность** — автоматическое обновление при изменении `Ref` элемента.
- **Поддержка нескольких типов** — одновременное прослушивание нескольких событий.
- **Автоматическая очистка** — эффективное управление памятью через систему реактивности.

## Инициализация

Создает новый экземпляр `EventRef`. Класс автоматически синхронизирует слушатели событий с состоянием переданных Vue `ref`. Если целевой элемент изменяется, `EventRef` автоматически перепривязывает событие.

### Ограничения дженериков (Generic Constraints)

- `E extends ElementOrWindow` — тип целевого элемента (например, `HTMLElement`, `Window`, или `Document`).
- `O extends Event` — тип объекта события (например, `MouseEvent`, `KeyboardEvent`).
- `D extends Record<string, any>` — тип пользовательских данных (`detail`), связанных с событием.

**Параметры:**
- `elementSelector?: RefOrNormal<ElementOrString<E> | undefined>` — целевой элемент или селектор (может быть реактивным).
- `elementSelectorControl?: RefOrNormal<ElementOrString<HTMLElement>>` — контрольный элемент. Если он удален из DOM, прослушивание прекращается.
- `type: string | string[] = ['click']` — тип события или массив типов.
- `listener?: EventListenerDetail<O, D>` — функция-обработчик.
- `options?: EventOptions` — параметры слушателя (`capture`, `passive`, `once`).
- `detail?: D` — дополнительные данные события.

```typescript
import { EventRef } from '@dxtmisha/functional'
import { ref, onMounted, onUnmounted } from 'vue'

// 1. Простая инициализация с Ref
const buttonRef = ref<HTMLButtonElement>()
const event = new EventRef(buttonRef, undefined, 'click', (e) => {
  console.log('Нажата кнопка:', e.target)
})

// 2. Использование нескольких событий и опций
const scrollEvent = new EventRef(
  window, 
  undefined, 
  ['scroll', 'resize'], 
  () => console.log('Изменение окна'),
  { passive: true }
)

onMounted(() => {
  event.start()
  scrollEvent.start()
})

onUnmounted(() => {
  event.stop()
  scrollEvent.stop()
})
```

## Управление жизненным циклом

Методы для контроля активности прослушивателей.

- `start(): this` — Активирует прослушивание событий. Если целевой элемент (`ref`) еще не примонтирован, слушатели будут добавлены автоматически сразу после его появления.
- `stop(): this` — Деактивирует прослушивание и удаляет все обработчики с текущего элемента.
- `toggle(activity: boolean): this` — Включает или выключает прослушивание в зависимости от переданного значения.
- `reset(): this` — Перезапускает прослушивание. Автоматически вызывается при изменении ключевых параметров (типа события, опций и т.д.).

## Состояние и получение данных

Методы для проверки текущего статуса объекта.

- `isActive(): boolean` — Возвращает `true`, если прослушивание событий в данный момент активно.
- `getElement(): E | undefined` — Возвращает текущий DOM-элемент или объект, на котором установлены слушатели.

## Конфигурация (Сеттеры)

Все методы этой группы поддерживают цепочку вызовов (чейнинг) и автоматически обновляют активные слушатели.

- `setElement(element: ElementOrString): this` — Динамически изменяет целевой элемент. При использовании в `EventRef` также поддерживает реактивные `ref`.
- `setElementControl(element: ElementOrString): this` — Устанавливает контрольный элемент. Если этот элемент удаляется из DOM, прослушивание событий на основном элементе автоматически прекращается (защита от утечек памяти).
- `setType(type: string | string[]): this` — Обновляет типы прослушиваемых событий (например, меняет `click` на `dblclick`).
- `setListener(listener: Function): this` — Изменяет функцию-обработчик события без перезапуска всего цикла.
- `setOptions(options: EventOptions): this` — Обновляет опции слушателя (`capture`, `passive`, `once`).
- `setDetail(detail: object): this` — Обновляет пользовательские данные, доступные внутри обработчика.

## Действия

- `dispatch(detail?: object): this` — Программно инициирует событие на целевом элементе. Если переданы данные в `detail`, они будут приоритетнее тех, что установлены через `setDetail`.

## Специальные события

`EventRef` (через базовый класс `EventItem`) предоставляет улучшенную обработку для некоторых типов событий:

### `resize`
В отличие от стандартного события `resize`, которое работает только на объекте `window`, здесь оно использует `ResizeObserver`. Это позволяет отслеживать изменение размеров любого конкретного DOM-элемента.

### `scroll-sync`
Оптимизированный вариант события прокрутки. Использует `requestAnimationFrame` для синхронизации вызова обработчика с частотой обновления экрана, что предотвращает "тормоза" при тяжелых вычислениях в процессе скролла.
