UNPKG

ypsilon-event-handler

Version:

A production-ready event handling system for web applications with memory leak prevention, and method chaining support

293 lines (267 loc) 10.3 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Simple Reactive Inputs - YpsilonEventHandler</title> <meta name="description" content="Simple reactive input example"> <link rel="icon" type="image/x-icon" href="./favicon.ico"> <link rel="stylesheet" type="text/css" href="./assets/main.css"> <style> body { font-family: sans-serif; background: #f9f9f9; margin: 0; padding: 0; } .demo-wrapper { max-width: 640px; margin: 0 auto; padding: 2rem 0 1rem; background: #f9f9f9; } h1, h2, h3 { margin-top: 0; } header, .demo-box { background: white; padding: 2rem; margin: 1rem 0; border-radius: 8px; border: 1px solid #ddd; } input { padding: 0.5rem; margin: 0.5rem 0; border: 1px solid #ccc; border-radius: 4px; width: 100%; box-sizing: border-box; &[type="checkbox"] { width: 20px; } } .output { background: #f0f8ff; padding: 1rem; margin: 0.5rem 0; border-radius: 4px; border: 1px solid #4CAF50; min-height: 40px; display: flex; align-items: center; } .output:empty::before { content: "Type in the input above..."; opacity: 0.5; font-style: italic; } .toggle-target { background: #fff3cd; border: 1px solid #ffeaa7; padding: 1rem; margin: 0.5rem 0; border-radius: 4px; transition: opacity 0.3s ease; } .toggle-target.hidden { display: none; } label { background: #f0f8ffaa; border: 1px solid #4CAF50aa; display: block; padding: .7rem; cursor: pointer; display: flex; align-items: center; gap: 0.5rem; border-radius: 4px; transition: all 0.2s ease; } label.active { background: #4CAF50; color: white; border-color: #45a049; font-weight: bold; } nav div { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; } nav a { margin: 0; padding: 8px; flex: 1 20%; white-space: nowrap; } </style> </head> <body> <div class="demo-wrapper"> <header> <h1>🔥 Reactive Inputs</h1> <p>How reactive is Y? <strong>Y!</strong></p> <hr /> <p style="margin-bottom:0">Type in any input and watch the target update instantly!</p> </header> <div class="demo-box"> <h2>Input 1 → Single Output</h2> <input type="text" name="demo-1" placeholder="Type something..." data-target="#output1"> <div class="output" id="output1"></div> </div> <div class="demo-box"> <h2>Input 2 → Multiple Outputs! 🤯</h2> <input type="text" name="demo-2" placeholder="Watch multiple elements update..." data-target="#output2, .output2-class"> <div class="output" id="output2"></div> <div class="output output2-class">Class-based target</div> <div class="output output2-class">Another class target</div> </div> <div class="demo-box"> <h2>Input 3 → Complex Selectors!</h2> <input type="text" name="demo-3" placeholder="Complex selector demo..." data-target=".output3, [data-reactive='advanced']"> <div class="output output3">Class selector target</div> <div class="output output3">Another class target</div> <div class="output" data-reactive="advanced">Data attribute target</div> <div class="output" data-reactive="advanced">Another data target</div> </div> <div class="demo-box"> <h3>☑️ Reactive Checkboxes</h3> <p>Toggle elements in and out of existence:</p> <label> <input type="checkbox" id="toggle1" data-toggle=".box1"> Show/Hide Yellow Box </label> <div class="toggle-target box1 hidden">🟡 This is Box 1! I can be toggled!</div> <hr /> <label> <input type="checkbox" id="toggle2" data-toggle=".box2, .box3"> Toggle Multiple Boxes </label> <div class="toggle-target box2 hidden">🟢 This is Box 2!</div> <div class="toggle-target box3 hidden">🔵 This is Box 3!</div> <hr /> <label> <input type="checkbox" id="toggle-all" data-toggle-checkboxes="#toggle1, #toggle2"> Master Toggle (Controls Other Checkboxes) </label> </div> <div class="demo-box"> <h3>🎯 The Magic</h3> <p><strong>Two listeners</strong> handle all inputs/checkboxes and update ALL matching targets automatically!</p> <p>✅ No individual listeners<br> ✅ No manual binding<br> ✅ Pure event delegation<br><strong>CSS selector support</strong><br><strong>Comma-separated multiple targets</strong><br><strong>Text inputs + checkbox toggles</strong></p> <h4>Reactive Patterns:</h4> <ul> <li><code>data-target="#myId"</code> → Update text content</li> <li><code>data-target=".myClass"</code> → Update multiple elements</li> <li><code>data-toggle=".box"</code> → Show/hide elements</li> <li><code>data-toggle=".box1, .box2"</code> → Toggle multiple elements</li> <li><code>data-toggle-checkboxes="#cb1, #cb2"</code> → Control other checkboxes</li> </ul> <p><strong>Safe and explicit</strong> - only affects exactly what you specify!</p> </div> <div class="nav-container"> <!-- Navigation to other examples --> <nav class="main-nav"> <div> <a href="./index.html" class="btn-primary">Start</a> <a href="./basic-example.html" class="btn-secondary">Basic Example</a> <a href="./reactive-y.html" class="btn-disabled">Reactive Demo</a> <a href="./single-listener-multiple-actions.html" class="btn-purple">Single Listener</a> <a href="./spa.html" class="btn-success">SPA Demo</a> <a href="./ai-reviews.html" class="btn-warning">AI Reviews</a> <a href="https://github.com/eypsilon/YpsilonEventHandler" class="btn-dark">GitHub</a> </div> </nav> </div> </div> <!-- Include YpsilonEventHandler --> <script src="https://cdn.jsdelivr.net/npm/ypsilon-event-handler@1.5.0/ypsilon-event-handler.min.js"></script> <script> class SimpleReactiveHandler extends YpsilonEventHandler { constructor() { super({ body: [ { type: 'input', debounce: 100 }, 'change' ] }); } handleInput(event, target) { // Basic validation - only handle inputs with data-target if (!target.dataset.target) return; const targetSelectors = target.dataset.target; // Split comma-separated selectors and update all matching elements targetSelectors.split(',').forEach(selector => { const trimmedSelector = selector.trim(); if (trimmedSelector) { const outputElements = document.querySelectorAll(trimmedSelector); outputElements.forEach(element => { element.textContent = target.value; }); } }); } handleChange(event, target) { // Handle checkbox active class on parent label if (target.type === 'checkbox') { const parentLabel = target.closest('label'); if (parentLabel) { if (target.checked) { parentLabel.classList.add('active'); } else { parentLabel.classList.remove('active'); } } } // Handle checkbox that controls other checkboxes if (target.type === 'checkbox' && target.dataset.toggleCheckboxes) { const checkboxSelectors = target.dataset.toggleCheckboxes; // Split comma-separated selectors and set all matching checkboxes checkboxSelectors.split(',').forEach(selector => { const trimmedSelector = selector.trim(); if (trimmedSelector) { const checkboxElements = document.querySelectorAll(trimmedSelector); checkboxElements.forEach(checkbox => { if (checkbox.type === 'checkbox') { checkbox.checked = target.checked; // Trigger change event to update their targets checkbox.dispatchEvent(new Event('change', { bubbles: true })); } }); } }); } // Handle regular checkbox toggles for elements if (target.type === 'checkbox' && target.dataset.toggle) { const toggleSelectors = target.dataset.toggle; // Split comma-separated selectors and toggle all matching elements toggleSelectors.split(',').forEach(selector => { const trimmedSelector = selector.trim(); if (trimmedSelector) { const toggleElements = document.querySelectorAll(trimmedSelector); toggleElements.forEach(element => { if (target.checked) { element.classList.remove('hidden'); } else { element.classList.add('hidden'); } }); } }); } } } // Initialize const handler = new SimpleReactiveHandler(); console.log('Simple reactive handler initialized!'); </script> </body> </html>