${section.name}
${section.items.map((item, index) => ` ${item.label || item}
`).join('')} ${item.label || item}
`).join(''); } attachEvents() { if (this.disabled) return; this.input.addEventListener('input', (e) => this.handleInput(e)); this.input.addEventListener('keydown', (e) => this.handleKeydown(e)); this.input.addEventListener('focus', () => this.handleFocus()); this.input.addEventListener('blur', (e) => this.handleBlur(e)); this.button.addEventListener('click', () => this.toggle()); if (this.clearButton) { this.clearButton.addEventListener('click', () => this.clear()); } this.listbox.addEventListener('click', (e) => this.handleItemClick(e)); this.listbox.addEventListener('mouseover', (e) => this.handleItemHover(e)); document.addEventListener('click', (e) => { if (!this.container.contains(e.target)) { this.close(); } }); } handleInput(e) { const value = e.target.value; this.filterItems(value); this.open(); this.clearError(); if (this.options.onInputChange) { this.options.onInputChange(value); } } handleKeydown(e) { switch (e.key) { case 'ArrowDown': e.preventDefault(); if (!this.isOpen) { this.open(); } else { this.moveSelection(1); } break; case 'ArrowUp': e.preventDefault(); if (this.isOpen) { this.moveSelection(-1); } break; case 'Enter': e.preventDefault(); if (this.isOpen && this.selectedIndex >= 0) { this.selectItem(this.selectedIndex); } break; case 'Escape': e.preventDefault(); this.close(); break; } } handleFocus() { if (this.options.menuTrigger === 'focus') { this.open(); } } handleBlur(e) { setTimeout(() => { if (!this.container.contains(document.activeElement)) { this.close(); this.validate(); } }, 100); } handleItemClick(e) { const item = e.target.closest('.react-aria-ListBoxItem'); if (item && !item.hasAttribute('data-disabled')) { const index = parseInt(item.dataset.index); this.selectItem(index); } } handleItemHover(e) { const item = e.target.closest('.react-aria-ListBoxItem'); if (item) { this.clearSelection(); item.setAttribute('data-hovered', ''); } } filterItems(query) { if (!query) { this.filteredItems = [...this.items]; } else { this.filteredItems = this.items.filter(item => { const text = item.label || item; return text.toLowerCase().includes(query.toLowerCase()); }); } this.updateListbox(); } updateListbox() { this.listbox.innerHTML = this.filteredItems.map((item, index) => ` ${item.label || item}
`).join(''); if (this.filteredItems.length === 0) { this.listbox.innerHTML = 'No results found
'; } } moveSelection(direction) { const items = this.listbox.querySelectorAll('.react-aria-ListBoxItem:not([style*="color: #999"])'); if (items.length === 0) return; this.clearSelection(); if (direction > 0) { this.selectedIndex = Math.min(this.selectedIndex + 1, items.length - 1); } else { this.selectedIndex = Math.max(this.selectedIndex - 1, 0); } if (this.selectedIndex >= 0) { items[this.selectedIndex].setAttribute('data-focused', ''); items[this.selectedIndex].scrollIntoView({ block: 'nearest' }); } } clearSelection() { this.listbox.querySelectorAll('.react-aria-ListBoxItem').forEach(item => { item.removeAttribute('data-focused'); item.removeAttribute('data-hovered'); }); } selectItem(index) { if (index >= 0 && index < this.filteredItems.length) { const item = this.filteredItems[index]; const value = item.value || item; const label = item.label || item; this.input.value = label; this.close(); if (this.options.onSelectionChange) { this.options.onSelectionChange(value); } } } open() { if (this.isOpen || this.disabled) return; this.isOpen = true; this.selectedIndex = -1; this.popover.style.display = 'block'; this.input.setAttribute('aria-expanded', 'true'); if (!this.input.value) { this.filterItems(''); } this.positionPopover(); } close() { if (!this.isOpen) return; this.isOpen = false; this.popover.style.display = 'none'; this.input.setAttribute('aria-expanded', 'false'); this.clearSelection(); } toggle() { if (this.isOpen) { this.close(); } else { this.open(); } } clear() { this.input.value = ''; this.clearError(); if (this.options.onSelectionChange) { this.options.onSelectionChange(null); } } positionPopover() { const inputRect = this.input.getBoundingClientRect(); this.popover.style.position = 'absolute'; this.popover.style.top = '100%'; this.popover.style.left = '0'; this.popover.style.right = '0'; this.popover.style.marginTop = '4px'; this.popover.style.setProperty('--trigger-width', inputRect.width + 'px'); } validate() { if (this.required && !this.input.value) { this.showError('This field is required'); return false; } if (!this.allowCustomValue && this.input.value) { const exists = this.items.some(item => { const label = item.label || item; return label === this.input.value; }); if (!exists) { this.showError('Please select a valid option'); return false; } } this.clearError(); return true; } showError(message) { this.errorElement.textContent = message; this.errorElement.style.display = 'block'; this.input.setAttribute('data-invalid', ''); } clearError() { this.errorElement.style.display = 'none'; this.input.removeAttribute('data-invalid'); } setValue(value) { this.input.value = value; } getValue() { return this.input.value; } setDisabled(disabled) { this.disabled = disabled; this.input.disabled = disabled; this.button.disabled = disabled; if (disabled) { this.container.querySelector('.react-aria-ComboBox').setAttribute('data-disabled', ''); this.close(); } else { this.container.querySelector('.react-aria-ComboBox').removeAttribute('data-disabled'); } } } // Initialize examples document.addEventListener('DOMContentLoaded', () => { // Basic Example new ComboBox(document.getElementById('basic-example'), { label: 'Favorite Animal', placeholder: 'Select an animal...', items: ['Aardvark', 'Cat', 'Dog', 'Kangaroo', 'Panda', 'Snake'], onSelectionChange: (value) => console.log('Selected:', value) }); // Dynamic Example new ComboBox(document.getElementById('dynamic-example'), { label: 'Engineering Major', items: [ { value: 1, label: 'Aerospace' }, { value: 2, label: 'Mechanical' }, { value: 3, label: 'Civil' }, { value: 4, label: 'Biomedical' }, { value: 5, label: 'Nuclear' }, { value: 6, label: 'Industrial' }, { value: 7, label: 'Chemical' }, { value: 8, label: 'Agricultural' }, { value: 9, label: 'Electrical' } ], onSelectionChange: (value) => console.log('Selected major:', value) }); // Custom Values Example new ComboBox(document.getElementById('custom-values-example'), { label: 'Favorite Animal (Custom Values Allowed)', placeholder: 'Type or select...', items: ['Red Panda', 'Cat', 'Dog', 'Aardvark', 'Kangaroo', 'Snake'], allowCustomValue: true, description: 'You can type your own value or select from the list.' }); // Sections Example new ComboBox(document.getElementById('sections-example'), { label: 'Preferred Fruit or Vegetable', sections: [ { name: 'Fruit', items: ['Apple', 'Banana', 'Orange', 'Grapes', 'Watermelon'] }, { name: 'Vegetable', items: ['Cabbage', 'Broccoli', 'Carrots', 'Lettuce', 'Spinach'] } ] }); // Validation Example const validationContainer = document.getElementById('validation-example'); validationContainer.innerHTML = ` `; const validationComboBox = new ComboBox(validationContainer.querySelector('#validation-combobox'), { label: 'Favorite Animal (Required)', items: ['Aardvark', 'Cat', 'Dog', 'Kangaroo', 'Panda', 'Snake'], required: true }); validationContainer.querySelector('form').addEventListener('submit', (e) => { e.preventDefault(); if (validationComboBox.validate()) { alert('Form submitted successfully!'); } }); // Disabled Example const disabledContainer = document.getElementById('disabled-example'); disabledContainer.innerHTML = ` Loading...
'; try { const response = await fetch(`https://swapi.dev/api/people/?search=${value}`); const data = await response.json(); asyncComboBox.items = data.results.map(person => ({ value: person.name, label: person.name })); asyncComboBox.filterItems(value); statusEl.innerHTML = `Found ${data.results.length} results`; } catch (error) { statusEl.innerHTML = 'Error loading data'; } } } }); }); ' width="100%" height="1200" frameborder="0" sandbox="allow-scripts allow-same-origin allow-popups allow-forms">