Enhance service detail UI with improved select and color controls
Refactors select dropdown functionality to use custom implementation Adds color dot support for color selection Improves keyboard navigation and interaction for select dropdowns Modernizes UI components with more flexible and interactive controls
This commit is contained in:
parent
120367acbb
commit
e9f3639c7c
5 changed files with 154 additions and 80 deletions
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Handles generic UI controls functionality:
|
||||
* - Toggle sliders (Ja/Nej switches)
|
||||
* - Select dropdowns (Popover API)
|
||||
* - Select dropdowns
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
@ -38,20 +38,20 @@ export class ControlsController {
|
|||
|
||||
/**
|
||||
* Initialize all select dropdowns on the page
|
||||
* Uses Popover API for dropdown behavior
|
||||
*/
|
||||
private initSelectDropdowns(): void {
|
||||
document.querySelectorAll('swp-select').forEach(select => {
|
||||
const trigger = select.querySelector('button');
|
||||
const popover = select.querySelector('[popover]') as HTMLElement | null;
|
||||
const dropdown = select.querySelector('swp-select-dropdown');
|
||||
const options = select.querySelectorAll('swp-select-option');
|
||||
|
||||
if (!trigger || !popover) return;
|
||||
if (!trigger || !dropdown) return;
|
||||
|
||||
// Update aria-expanded on toggle
|
||||
popover.addEventListener('toggle', (e: Event) => {
|
||||
const event = e as ToggleEvent;
|
||||
trigger.setAttribute('aria-expanded', event.newState === 'open' ? 'true' : 'false');
|
||||
// Toggle dropdown on button click
|
||||
trigger.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
const isOpen = select.classList.toggle('open');
|
||||
trigger.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
|
||||
});
|
||||
|
||||
// Handle option selection
|
||||
|
|
@ -70,11 +70,18 @@ export class ControlsController {
|
|||
valueEl.textContent = label;
|
||||
}
|
||||
|
||||
// Update color dot if present (for color pickers)
|
||||
const triggerDot = trigger.querySelector('swp-color-dot');
|
||||
if (triggerDot && value) {
|
||||
triggerDot.className = `is-${value}`;
|
||||
}
|
||||
|
||||
// Update data-value on select element
|
||||
(select as HTMLElement).dataset.value = value;
|
||||
|
||||
// Close popover
|
||||
popover.hidePopover();
|
||||
// Close dropdown
|
||||
select.classList.remove('open');
|
||||
trigger.setAttribute('aria-expanded', 'false');
|
||||
|
||||
// Dispatch custom event
|
||||
select.dispatchEvent(new CustomEvent('change', {
|
||||
|
|
@ -84,5 +91,54 @@ export class ControlsController {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Click outside to close any open dropdown
|
||||
document.addEventListener('click', () => {
|
||||
this.closeAllSelects();
|
||||
});
|
||||
|
||||
// Keyboard navigation
|
||||
document.addEventListener('keydown', (e) => {
|
||||
const openSelect = document.querySelector('swp-select.open');
|
||||
if (!openSelect) return;
|
||||
|
||||
// Escape to close
|
||||
if (e.key === 'Escape') {
|
||||
this.closeAllSelects();
|
||||
return;
|
||||
}
|
||||
|
||||
// Letter key to jump to option
|
||||
if (e.key.length === 1 && /[a-zA-ZæøåÆØÅ]/.test(e.key)) {
|
||||
const options = openSelect.querySelectorAll('swp-select-option');
|
||||
const letter = e.key.toLowerCase();
|
||||
|
||||
for (const option of options) {
|
||||
const text = option.textContent?.trim().toLowerCase() || '';
|
||||
if (text.startsWith(letter)) {
|
||||
// Scroll into view and highlight
|
||||
option.scrollIntoView({ block: 'nearest' });
|
||||
options.forEach(o => o.classList.remove('highlighted'));
|
||||
option.classList.add('highlighted');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enter to select highlighted option
|
||||
if (e.key === 'Enter') {
|
||||
const highlighted = openSelect.querySelector('swp-select-option.highlighted') as HTMLElement;
|
||||
if (highlighted) {
|
||||
highlighted.click();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private closeAllSelects(): void {
|
||||
document.querySelectorAll('swp-select.open').forEach(select => {
|
||||
select.classList.remove('open');
|
||||
select.querySelector('button')?.setAttribute('aria-expanded', 'false');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue