Now.js Framework Documentation

Now.js Framework Documentation

EventSystemManager - DOM Event System

EN 31 Oct 2025 01:20

EventSystemManager - DOM Event System

Documentation for EventSystemManager, a high-performance DOM event management system.

📋 Table of Contents

  1. Overview
  2. Installation and Import
  3. Basic Usage
  4. Event Delegation
  5. Keyboard Events
  6. Window Events
  7. Performance Optimization
  8. Memory Management
  9. Priority System
  10. Configuration
  11. Usage Examples
  12. API Reference
  13. Best Practices

Overview

EventSystemManager is a high-performance DOM event management system designed with advanced features beyond standard addEventListener.

Key Features

  • Event Delegation: Centralized event management
  • Auto Cleanup: Automatically removes handlers when elements are removed
  • Memory Management: Monitors and manages memory usage
  • Priority System: Controls handler execution order
  • UI Event Optimization: Uses requestAnimationFrame for UI events
  • Keyboard Event Enhancement: Comprehensive keyboard event information
  • Throttle/Debounce: Built-in event rate limiting
  • Component Integration: Integrates with Now.js Components
  • MutationObserver: Tracks DOM changes
  • Performance Monitoring: Measures and tracks performance

Differences from EventManager

Feature EventSystemManager EventManager
Purpose DOM Events Application Events
Main API addHandler(), removeHandler() on(), emit(), off()
Event Types DOM events (click, submit, etc.) Custom events
Target DOM elements Application logic
Event Delegation ✅ Supported ❌ Not supported
Auto Cleanup ✅ Supported ⚠️ Manual
Memory Monitoring ✅ Supported ❌ Not supported
UI Optimization ✅ requestAnimationFrame ❌ Not supported

When to Use EventSystemManager

Use EventSystemManager when:

  • Managing DOM Events (click, submit, input, etc.)
  • Need Event Delegation
  • Need Auto Cleanup when elements are removed
  • Need Performance Optimization
  • Need automatic Memory Management
  • Need Priority-based event handling

Don't use EventSystemManager when:

  • Need Custom Application Events (use EventManager)
  • Need Pattern Matching (use EventManager)
  • Need Middleware (use EventManager)
  • Need Event Groups (use EventManager)

Installation and Import

EventSystemManager loads with Now.js Framework and initializes automatically:

// No need to import - ready to use immediately
console.log(window.EventSystemManager); // EventSystemManager object

// Access through Now.js
const eventSystem = Now.getManager('eventsystem');

Dependencies

EventSystemManager requires these dependencies:

  • ErrorManager - For error handling

Initialization

EventSystemManager initializes automatically when Now.js loads:

// Auto-initialized
EventSystemManager.init();

// Or init with custom config
EventSystemManager.init({
  delegation: {
    enabled: true,
    maxDelegationDepth: 10
  },
  memoryManagement: {
    maxHandlersPerElement: 100,
    maxCacheSize: 1000
  }
});

Basic Usage

1. Add Event Handler

// Basic
const element = document.querySelector('#my-button');
const handlerId = EventSystemManager.addHandler(element, 'click', (event) => {
  console.log('Button clicked!', event);
});

// With options
const id = EventSystemManager.addHandler(element, 'click', (event) => {
  console.log('Clicked:', event.target);
}, {
  capture: false,
  once: false,
  passive: true,
  priority: 10
});

2. Remove Event Handler

// Remove by handler ID
EventSystemManager.removeHandler(handlerId);

// Remove all handlers for a component
EventSystemManager.removeComponentHandlers('my-component-id');

3. Window Events

// Window events are handled automatically
EventSystemManager.addHandler(window, 'resize', (event) => {
  console.log('Window resized');
});

EventSystemManager.addHandler(window, 'scroll', (event) => {
  console.log('Window scrolled');
});

4. Document Events

// Document events
EventSystemManager.addHandler(document, 'click', (event) => {
  console.log('Document clicked');
});

Event Delegation

Event Delegation allows managing events of child elements from a parent.

Basic Delegation

// Capture clicks on child elements matching selector
const container = document.querySelector('#container');

EventSystemManager.addHandler(container, 'click', (event) => {
  console.log('Button clicked:', event.delegateTarget);
}, {
  selector: '.item-button' // Only triggers on .item-button within container
});

Use Cases for Delegation

1. Dynamic Lists

// List with dynamically added/removed items
const list = document.querySelector('#todo-list');

// Handle clicks on delete buttons
EventSystemManager.addHandler(list, 'click', (event) => {
  const item = event.delegateTarget;
  const itemId = item.dataset.id;
  deleteItem(itemId);
}, {
  selector: '.delete-button'
});

// Handle clicks on checkboxes
EventSystemManager.addHandler(list, 'click', (event) => {
  const checkbox = event.delegateTarget;
  toggleItemComplete(checkbox);
}, {
  selector: '.item-checkbox'
});

2. Tables

// Handle clicks on table rows
const table = document.querySelector('#data-table');

EventSystemManager.addHandler(table, 'click', (event) => {
  const row = event.delegateTarget;
  const rowId = row.dataset.id;
  showRowDetails(rowId);
}, {
  selector: 'tbody tr'
});

// Handle clicks on edit buttons
EventSystemManager.addHandler(table, 'click', (event) => {
  const button = event.delegateTarget;
  const rowId = button.closest('tr').dataset.id;
  editRow(rowId);
}, {
  selector: '.edit-button'
});

3. Modal/Dialog

// Handle clicks on backdrop to close modal
EventSystemManager.addHandler(document.body, 'click', (event) => {
  if (event.delegateTarget.classList.contains('modal-backdrop')) {
    closeModal();
  }
}, {
  selector: '.modal-backdrop'
});

Keyboard Events

EventSystemManager has special keyboard event enhancement.

Enhanced Keyboard Events

EventSystemManager.addHandler(input, 'keydown', (event) => {
  const enhanced = event.originalEvent._enhanced;

  console.log('Key:', enhanced.key);
  console.log('Code:', enhanced.code);

  // Helper properties
  if (enhanced.isEnter) {
    console.log('Enter pressed');
  }

  if (enhanced.isShiftEnter) {
    console.log('Shift+Enter pressed');
  }

  if (enhanced.isCtrlEnter) {
    console.log('Ctrl+Enter pressed');
  }

  if (enhanced.isTab) {
    console.log('Tab pressed');
  }

  if (enhanced.isShiftTab) {
    console.log('Shift+Tab pressed');
  }

  if (enhanced.isArrowKey) {
    console.log('Arrow key pressed:', enhanced.key);
  }

  // Modifiers
  if (enhanced.ctrlKey) console.log('Ctrl is held');
  if (enhanced.altKey) console.log('Alt is held');
  if (enhanced.shiftKey) console.log('Shift is held');
  if (enhanced.metaKey) console.log('Meta/Cmd is held');
});

Keyboard Shortcuts

// Submit form with Ctrl+Enter
EventSystemManager.addHandler(textarea, 'keydown', (event) => {
  const enhanced = event.originalEvent._enhanced;

  if (enhanced.isCtrlEnter) {
    event.preventDefault();
    submitForm();
  }
});

// Tab navigation with Shift+Tab
EventSystemManager.addHandler(form, 'keydown', (event) => {
  const enhanced = event.originalEvent._enhanced;

  if (enhanced.isShiftTab) {
    // Custom tab navigation
    navigateToPreviousField();
  }
});

// Close on Escape
EventSystemManager.addHandler(document, 'keydown', (event) => {
  if (event.key === 'Escape') {
    closeAllModals();
  }
});

Window Events

Handle window-level events such as resize, scroll, popstate.

Supported Window Events

// Resize
EventSystemManager.addHandler(window, 'resize', (event) => {
  console.log('Window resized');
  handleResize();
});

// Scroll
EventSystemManager.addHandler(window, 'scroll', (event) => {
  console.log('Window scrolled');
  handleScroll();
});

// Popstate (history navigation)
EventSystemManager.addHandler(window, 'popstate', (event) => {
  console.log('History state changed');
  handlePopState(event);
});

// Hashchange
EventSystemManager.addHandler(window, 'hashchange', (event) => {
  console.log('Hash changed');
  handleHashChange();
});

// Load
EventSystemManager.addHandler(window, 'load', (event) => {
  console.log('Window loaded');
  initialize();
});

// Online/Offline
EventSystemManager.addHandler(window, 'online', (event) => {
  console.log('Connection restored');
  syncData();
});

EventSystemManager.addHandler(window, 'offline', (event) => {
  console.log('Connection lost');
  showOfflineMessage();
});

Performance Optimization

EventSystemManager has several performance enhancement mechanisms.

UI Event Optimization

UI events (resize, scroll, mousemove) use requestAnimationFrame:

// Optimized automatically
EventSystemManager.addHandler(window, 'scroll', (event) => {
  // Runs in requestAnimationFrame
  updateScrollPosition();
});

EventSystemManager.addHandler(window, 'resize', (event) => {
  // Batched in requestAnimationFrame
  recalculateLayout();
});

EventSystemManager.addHandler(element, 'mousemove', (event) => {
  // Queued and processed together
  updateMousePosition(event);
});

Throttle and Debounce

// Throttle - limit execution rate
let lastTime = 0;
EventSystemManager.addHandler(window, 'scroll', (event) => {
  const now = Date.now();
  if (now - lastTime < 100) return; // throttle 100ms

  lastTime = now;
  handleScroll();
});

// Debounce - wait until stopped then execute
let debounceTimer;
EventSystemManager.addHandler(window, 'resize', (event) => {
  clearTimeout(debounceTimer);
  debounceTimer = setTimeout(() => {
    handleResize();
  }, 200); // debounce 200ms
});

Event Filtering

EventSystemManager has built-in event filtering:

// Configuration
EventSystemManager.config.filtering = {
  enabled: true,
  maxThrottleRate: 60, // events per second
  debounceWait: 100,
  highFrequencyEvents: new Set([
    'mousemove',
    'scroll',
    'resize',
    'touchmove',
    'pointermove'
  ])
};

Memory Management

EventSystemManager manages memory automatically.

Auto Cleanup

// Handlers are automatically removed when element is removed from DOM
const element = document.createElement('div');
document.body.appendChild(element);

const id = EventSystemManager.addHandler(element, 'click', handler);

// Remove element - handler is automatically removed
element.remove();

Manual Cleanup

// Remove specific handler
EventSystemManager.removeHandler(handlerId);

// Remove all handlers for a component
EventSystemManager.removeComponentHandlers('component-id');

// Cleanup everything
EventSystemManager.cleanup();

// Destroy
EventSystemManager.destroy();

Memory Monitoring

// Check memory usage
const stats = EventSystemManager.gatherMemoryStats();
console.log('Handlers:', stats.handlerCount);
console.log('Cache size:', stats.cacheSize);
console.log('WeakMap size:', stats.weakMapSize);

// Memory stats
console.log(EventSystemManager.state.memoryStats);
// {
//   handlerCount: 42,
//   cacheSize: 15,
//   weakMapSize: 8,
//   lastGC: 1698765432100,
//   peakMemoryUsage: 50,
//   memoryWarnings: 0
// }

Garbage Collection

// Manual GC trigger
EventSystemManager.performGC();

// Auto GC configuration
EventSystemManager.config.memoryManagement = {
  checkInterval: 30000,      // Check every 30 seconds
  maxHandlersPerElement: 100, // Max handlers per element
  maxCacheSize: 1000,        // Max cache size
  gcThreshold: 0.8,          // Trigger GC at 80%
  detailedTracking: true     // Enable detailed logging
};

Priority System

Control handler execution order.

Priority Values

// High priority - executes first
EventSystemManager.addHandler(element, 'click', validationHandler, {
  priority: 100
});

// Medium priority
EventSystemManager.addHandler(element, 'click', transformHandler, {
  priority: 50
});

// Low priority - executes last
EventSystemManager.addHandler(element, 'click', submitHandler, {
  priority: 10
});

// Default priority (0) - executes last
EventSystemManager.addHandler(element, 'click', loggingHandler);

Use Cases for Priority

1. Form Validation Pipeline

// Validate first
EventSystemManager.addHandler(form, 'submit', (event) => {
  if (!validateForm()) {
    event.preventDefault();
    event.stopImmediatePropagation();
  }
}, {priority: 100});

// Transform data
EventSystemManager.addHandler(form, 'submit', (event) => {
  transformFormData();
}, {priority: 50});

// Submit - executes last
EventSystemManager.addHandler(form, 'submit', (event) => {
  submitFormData();
}, {priority: 10});

2. Click Handlers

// Check permissions first
EventSystemManager.addHandler(button, 'click', (event) => {
  if (!hasPermission()) {
    event.preventDefault();
    event.stopPropagation();
    showPermissionError();
  }
}, {priority: 100});

// Actual action
EventSystemManager.addHandler(button, 'click', (event) => {
  performAction();
}, {priority: 50});

Configuration

Configuration Options

const config = {
  cleanupInterval: 600000,    // Cleanup interval (ms)
  maxMemoryUsage: 52428800,   // Max memory (50MB)

  delegation: {
    enabled: true,
    matchingStrategy: 'closestFirst',
    maxDelegationDepth: 10,
    optimizeSelectors: true,
    rootElement: document.body
  },

  memoryManagement: {
    checkInterval: 30000,
    maxHandlersPerElement: 100,
    maxCacheSize: 1000,
    gcThreshold: 0.8,
    detailedTracking: true
  },

  filtering: {
    enabled: true,
    maxThrottleRate: 60,
    debounceWait: 100,
    highFrequencyEvents: null  // Set or null
  }
};

Update Configuration

// Update individual settings
EventSystemManager.config.memoryManagement.maxHandlersPerElement = 200;
EventSystemManager.config.delegation.maxDelegationDepth = 15;

// Update filtering
EventSystemManager.config.filtering.enabled = true;
EventSystemManager.config.filtering.maxThrottleRate = 30;

Usage Examples

1. Form Handling

const form = document.querySelector('#registration-form');

// Submit handler
EventSystemManager.addHandler(form, 'submit', (event) => {
  event.preventDefault();

  // Validate
  if (!validateForm(form)) {
    showErrors();
    return;
  }

  // Submit
  const formData = new FormData(form);
  submitRegistration(formData);
}, {
  priority: 50
});

// Real-time validation
const inputs = form.querySelectorAll('input');
inputs.forEach(input => {
  EventSystemManager.addHandler(input, 'blur', (event) => {
    validateField(event.target);
  });

  EventSystemManager.addHandler(input, 'input', (event) => {
    clearFieldError(event.target);
  });
});

2. Dynamic List with Delegation

const todoList = document.querySelector('#todo-list');

// Add item
EventSystemManager.addHandler(todoList, 'click', (event) => {
  const item = event.delegateTarget;
  const itemId = item.dataset.id;
  addTodoItem(itemId);
}, {
  selector: '.add-button'
});

// Toggle complete
EventSystemManager.addHandler(todoList, 'click', (event) => {
  const checkbox = event.delegateTarget;
  const itemId = checkbox.closest('.todo-item').dataset.id;
  toggleComplete(itemId, checkbox.checked);
}, {
  selector: '.todo-checkbox'
});

// Delete item
EventSystemManager.addHandler(todoList, 'click', (event) => {
  const button = event.delegateTarget;
  const itemId = button.closest('.todo-item').dataset.id;
  deleteItem(itemId);
}, {
  selector: '.delete-button'
});

// Edit item
EventSystemManager.addHandler(todoList, 'click', (event) => {
  const button = event.delegateTarget;
  const itemId = button.closest('.todo-item').dataset.id;
  editItem(itemId);
}, {
  selector: '.edit-button'
});

3. Keyboard Navigation

const searchBox = document.querySelector('#search-box');
const results = document.querySelector('#search-results');

EventSystemManager.addHandler(searchBox, 'keydown', (event) => {
  const enhanced = event.originalEvent._enhanced;

  if (enhanced.isArrowKey) {
    event.preventDefault();

    if (enhanced.key === 'ArrowDown') {
      focusNextResult();
    } else if (enhanced.key === 'ArrowUp') {
      focusPreviousResult();
    }
  }

  if (enhanced.isEnter) {
    const focused = results.querySelector('.focused');
    if (focused) {
      selectResult(focused);
    }
  }

  if (event.key === 'Escape') {
    closeResults();
  }
});

4. Scroll Handling

// Infinite scroll
let isLoading = false;
EventSystemManager.addHandler(window, 'scroll', (event) => {
  if (isLoading) return;

  const scrollPosition = window.scrollY + window.innerHeight;
  const documentHeight = document.documentElement.scrollHeight;

  if (scrollPosition >= documentHeight - 200) {
    isLoading = true;
    loadMoreContent().then(() => {
      isLoading = false;
    });
  }
});

// Sticky header
const header = document.querySelector('#header');
EventSystemManager.addHandler(window, 'scroll', (event) => {
  if (window.scrollY > 100) {
    header.classList.add('sticky');
  } else {
    header.classList.remove('sticky');
  }
});

5. Drag and Drop

const draggable = document.querySelector('.draggable');
const dropzone = document.querySelector('.dropzone');

// Drag start
EventSystemManager.addHandler(draggable, 'dragstart', (event) => {
  event.originalEvent.dataTransfer.effectAllowed = 'move';
  event.originalEvent.dataTransfer.setData('text/html', event.target.innerHTML);
  event.target.classList.add('dragging');
});

// Drag end
EventSystemManager.addHandler(draggable, 'dragend', (event) => {
  event.target.classList.remove('dragging');
});

// Drag over
EventSystemManager.addHandler(dropzone, 'dragover', (event) => {
  event.preventDefault();
  event.originalEvent.dataTransfer.dropEffect = 'move';
  dropzone.classList.add('drag-over');
});

// Drag leave
EventSystemManager.addHandler(dropzone, 'dragleave', (event) => {
  dropzone.classList.remove('drag-over');
});

// Drop
EventSystemManager.addHandler(dropzone, 'drop', (event) => {
  event.preventDefault();
  dropzone.classList.remove('drag-over');

  const data = event.originalEvent.dataTransfer.getData('text/html');
  handleDrop(data);
});

6. Modal Management

// Open modal
function openModal(modalId) {
  const modal = document.querySelector(`#${modalId}`);
  modal.classList.add('active');

  // Close on backdrop click
  const backdropId = EventSystemManager.addHandler(modal, 'click', (event) => {
    if (event.target === modal) {
      closeModal(modalId);
      EventSystemManager.removeHandler(backdropId);
    }
  });

  // Close on Escape
  const escapeId = EventSystemManager.addHandler(document, 'keydown', (event) => {
    if (event.key === 'Escape') {
      closeModal(modalId);
      EventSystemManager.removeHandler(escapeId);
    }
  });
}

function closeModal(modalId) {
  const modal = document.querySelector(`#${modalId}`);
  modal.classList.remove('active');
}

7. Context Menu

const contextMenu = document.querySelector('#context-menu');

// Show context menu
EventSystemManager.addHandler(document, 'contextmenu', (event) => {
  if (!event.target.closest('.has-context-menu')) return;

  event.preventDefault();

  contextMenu.style.left = event.originalEvent.pageX + 'px';
  contextMenu.style.top = event.originalEvent.pageY + 'px';
  contextMenu.classList.add('active');
});

// Hide context menu
EventSystemManager.addHandler(document, 'click', (event) => {
  if (!event.target.closest('#context-menu')) {
    contextMenu.classList.remove('active');
  }
});

// Context menu actions
EventSystemManager.addHandler(contextMenu, 'click', (event) => {
  const action = event.delegateTarget.dataset.action;
  handleContextMenuAction(action);
  contextMenu.classList.remove('active');
}, {
  selector: '[data-action]'
});

8. Table Sorting

const table = document.querySelector('#data-table');

EventSystemManager.addHandler(table, 'click', (event) => {
  const th = event.delegateTarget;
  const columnIndex = Array.from(th.parentElement.children).indexOf(th);
  const currentSort = th.dataset.sort || 'none';

  // Toggle sort direction
  let newSort;
  if (currentSort === 'none') newSort = 'asc';
  else if (currentSort === 'asc') newSort = 'desc';
  else newSort = 'none';

  // Update UI
  table.querySelectorAll('th').forEach(header => {
    header.dataset.sort = 'none';
  });
  th.dataset.sort = newSort;

  // Sort table
  sortTable(table, columnIndex, newSort);
}, {
  selector: 'th[data-sortable]'
});

9. File Upload with Drag and Drop

const dropzone = document.querySelector('#file-dropzone');

// Prevent default drag behaviors
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
  EventSystemManager.addHandler(dropzone, eventName, (event) => {
    event.preventDefault();
    event.stopPropagation();
  });
});

// Highlight dropzone
['dragenter', 'dragover'].forEach(eventName => {
  EventSystemManager.addHandler(dropzone, eventName, (event) => {
    dropzone.classList.add('highlight');
  });
});

['dragleave', 'drop'].forEach(eventName => {
  EventSystemManager.addHandler(dropzone, eventName, (event) => {
    dropzone.classList.remove('highlight');
  });
});

// Handle drop
EventSystemManager.addHandler(dropzone, 'drop', (event) => {
  const files = event.originalEvent.dataTransfer.files;
  handleFiles(files);
});

// Click to upload
EventSystemManager.addHandler(dropzone, 'click', (event) => {
  const input = document.createElement('input');
  input.type = 'file';
  input.multiple = true;
  input.onchange = (e) => handleFiles(e.target.files);
  input.click();
});

10. Responsive Navigation

const nav = document.querySelector('#main-nav');
const toggle = document.querySelector('#nav-toggle');

// Toggle mobile menu
EventSystemManager.addHandler(toggle, 'click', (event) => {
  nav.classList.toggle('active');
});

// Close on outside click
EventSystemManager.addHandler(document, 'click', (event) => {
  if (!event.target.closest('#main-nav') &&
      !event.target.closest('#nav-toggle')) {
    nav.classList.remove('active');
  }
});

// Close on Escape
EventSystemManager.addHandler(document, 'keydown', (event) => {
  if (event.key === 'Escape') {
    nav.classList.remove('active');
  }
});

// Handle resize
EventSystemManager.addHandler(window, 'resize', (event) => {
  if (window.innerWidth > 768) {
    nav.classList.remove('active');
  }
});

API Reference

Configuration

{
  cleanupInterval: number,           // Cleanup interval (ms)
  maxMemoryUsage: number,           // Max memory usage (bytes)

  delegation: {
    enabled: boolean,                // Enable delegation
    matchingStrategy: string,        // 'closestFirst'
    maxDelegationDepth: number,     // Max depth
    optimizeSelectors: boolean,      // Optimize selectors
    rootElement: HTMLElement         // Root element
  },

  memoryManagement: {
    checkInterval: number,           // Check interval (ms)
    maxHandlersPerElement: number,  // Max handlers per element
    maxCacheSize: number,           // Max cache size
    gcThreshold: number,            // GC threshold (0-1)
    detailedTracking: boolean       // Detailed tracking
  },

  filtering: {
    enabled: boolean,               // Enable filtering
    maxThrottleRate: number,        // Max events per second
    debounceWait: number,          // Debounce wait (ms)
    highFrequencyEvents: Set       // High frequency events
  }
}

Methods

Core Methods

// Initialize
init(): EventSystemManager

// Add handler
addHandler(
  element: Element|Window|Document,
  type: string,
  handler: function,
  options?: {
    capture?: boolean,
    once?: boolean,
    passive?: boolean,
    priority?: number,
    componentId?: string,
    selector?: string
  }
): number

// Remove handler
removeHandler(id: number): boolean

// Remove component handlers
removeComponentHandlers(componentId: string): void

Cleanup Methods

// Manual cleanup
cleanup(): void

// Remove element handlers
removeElementHandlers(element: Element): void

// Destroy
destroy(): void

Memory Methods

// Gather memory stats
gatherMemoryStats(): object

// Check memory usage
checkMemoryUsage(): void

// Perform GC
performGC(): void

Event Object

{
  type: string,              // Event type
  key: string,               // Key (keyboard events)
  shiftKey: boolean,         // Shift key pressed
  ctrlKey: boolean,          // Ctrl key pressed
  altKey: boolean,           // Alt key pressed
  metaKey: boolean,          // Meta key pressed
  target: Element,           // Event target
  currentTarget: Element,    // Current target
  delegateTarget: Element,   // Delegate target
  timestamp: number,         // Timestamp
  originalEvent: Event,      // Original DOM event

  preventDefault(): void,
  stopPropagation(): void,
  stopImmediatePropagation(): void,
  matches(selector: string): boolean
}

Handler Options

{
  capture: boolean,      // Capture phase
  once: boolean,         // Execute once
  passive: boolean,      // Passive listener
  priority: number,      // Priority (higher = first)
  componentId: string,   // Component ID
  selector: string       // Delegation selector
}

Best Practices

1. ✅ Use Event Delegation

// ❌ Bad: separate handlers for each element
items.forEach(item => {
  EventSystemManager.addHandler(item, 'click', handler);
});

// ✅ Good: use delegation
EventSystemManager.addHandler(container, 'click', handler, {
  selector: '.item'
});

2. ✅ Cleanup When Destroying Component

// ✅ Good: store handler IDs
const MyComponent = {
  handlerIds: [],

  init() {
    const id1 = EventSystemManager.addHandler(this.element, 'click', handler);
    const id2 = EventSystemManager.addHandler(this.button, 'submit', handler);

    this.handlerIds.push(id1, id2);
  },

  destroy() {
    this.handlerIds.forEach(id => {
      EventSystemManager.removeHandler(id);
    });
  }
};

3. ✅ Use Component ID

// ✅ Good: use componentId for easy cleanup
const componentId = 'my-component-123';

EventSystemManager.addHandler(element, 'click', handler, {
  componentId
});

// Cleanup entire component at once
EventSystemManager.removeComponentHandlers(componentId);

4. ✅ Use Priority Appropriately

// ✅ Good: validation before submit
EventSystemManager.addHandler(form, 'submit', validateHandler, {
  priority: 100
});

EventSystemManager.addHandler(form, 'submit', submitHandler, {
  priority: 10
});

5. ✅ Use Passive for Scroll/Touch

// ✅ Good: passive for better performance
EventSystemManager.addHandler(element, 'touchstart', handler, {
  passive: true
});

EventSystemManager.addHandler(window, 'scroll', handler, {
  passive: true
});

6. ✅ Throttle/Debounce UI Events

// ✅ Good: throttle scroll event
let lastTime = 0;
EventSystemManager.addHandler(window, 'scroll', (event) => {
  const now = Date.now();
  if (now - lastTime < 100) return;

  lastTime = now;
  handleScroll();
});

7. ✅ Use Once for One-time Events

// ✅ Good: once for one-time events
EventSystemManager.addHandler(button, 'click', handler, {
  once: true
});

8. ✅ Manage Memory Carefully

// ✅ Good: monitor memory usage
setInterval(() => {
  const stats = EventSystemManager.gatherMemoryStats();

  if (stats.handlerCount > 500) {
    console.warn('Too many handlers:', stats.handlerCount);
  }
}, 60000);

9. ✅ Use stopPropagation Carefully

// ⚠️ Careful: stopPropagation may prevent other handlers
EventSystemManager.addHandler(button, 'click', (event) => {
  // Only use when necessary
  event.stopPropagation();
});

10. ✅ Test on Multiple Devices

// ✅ Good: support both mouse and touch
EventSystemManager.addHandler(element, 'click', handleClick);
EventSystemManager.addHandler(element, 'touchend', handleClick);

Summary

When to Use EventSystemManager

Use Case Use EventSystemManager? Notes
Manage DOM Events ✅ Yes click, submit, input, etc.
Event Delegation ✅ Yes Dynamic content
Auto Cleanup ✅ Yes Memory management
Performance Optimization ✅ Yes UI events
Keyboard Handling ✅ Yes Enhanced keyboard events
Custom Application Events ❌ No Use EventManager
Pattern Matching ❌ No Use EventManager
Middleware ❌ No Use EventManager

Key Features

Feature Supported Notes
Event Delegation Selector-based
Auto Cleanup MutationObserver
Memory Management Auto GC
Priority System Ordered execution
UI Optimization requestAnimationFrame
Keyboard Enhancement Helper properties
Throttle/Debounce Built-in filtering
Component Integration Component IDs