@scania/tegel
Version:
Tegel Design System
305 lines (304 loc) • 14 kB
JavaScript
function setupOptionTabindex(container, selector = '.tl-dropdown__option', disableCheckboxes = false) {
container.querySelectorAll(selector).forEach((option) => {
const isDisabled = option.classList.contains('tl-dropdown__option--disabled');
option.setAttribute('tabindex', isDisabled ? '-1' : '0');
if (disableCheckboxes) {
const checkbox = option.querySelector('.tl-checkbox__input');
if (checkbox)
checkbox.setAttribute('tabindex', '-1');
}
});
}
function setupClickOutside(root, closeCallback) {
document.addEventListener('click', (e) => {
if (!root.contains(e.target))
closeCallback();
});
root.addEventListener('focusout', (e) => {
setTimeout(() => {
if (!root.contains(e.relatedTarget))
closeCallback();
}, 20);
});
}
function handleKeyboardSelection(e, selector, callback) {
var _a;
if (e.key === 'Enter' || e.key === ' ') {
const focusedOption = (_a = document.activeElement) === null || _a === void 0 ? void 0 : _a.closest(selector);
if (focusedOption) {
e.preventDefault();
callback(focusedOption);
}
}
}
function createToggleDropdown(trigger) {
return () => {
const isOpen = trigger.getAttribute('aria-expanded') === 'true';
trigger.setAttribute('aria-expanded', isOpen ? 'false' : 'true');
};
}
function createCloseDropdown(trigger) {
return () => trigger.setAttribute('aria-expanded', 'false');
}
function getSelectedCheckboxLabels(container) {
return Array.from(container.querySelectorAll('.tl-checkbox__input:checked'))
.map((checkbox) => {
var _a, _b;
const label = (_a = checkbox.closest('.tl-dropdown__option')) === null || _a === void 0 ? void 0 : _a.querySelector('.tl-checkbox__label');
return ((_b = label === null || label === void 0 ? void 0 : label.textContent) === null || _b === void 0 ? void 0 : _b.trim()) || '';
})
.filter(Boolean)
.join(', ');
}
function setupInputWrapperToggle(inputWrapper, input, openDropdown, closeDropdown, filterOptions) {
inputWrapper === null || inputWrapper === void 0 ? void 0 : inputWrapper.addEventListener('mousedown', (e) => {
const target = e.target;
if (target === input || target.closest('.tl-dropdown__input-clear') || input.disabled)
return;
e.preventDefault();
e.stopPropagation();
const isOpen = input.getAttribute('aria-expanded') === 'true';
if (isOpen) {
closeDropdown();
input.blur();
}
else {
openDropdown();
input.focus();
filterOptions();
}
});
}
function setupClearButton(clearButton, callback) {
clearButton === null || clearButton === void 0 ? void 0 : clearButton.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
callback();
});
}
function createUpdateClearButtonTabindex(input, clearButton) {
return () => {
const isVisible = input.getAttribute('aria-expanded') === 'true' && input.value.trim() !== '';
clearButton === null || clearButton === void 0 ? void 0 : clearButton.setAttribute('tabindex', isVisible ? '0' : '-1');
};
}
function setupInputEvents(input, openDropdown, filterOptions, updateClearButtonTabindex, getInitialValue) {
input.addEventListener('focus', () => {
openDropdown();
const initialValue = getInitialValue === null || getInitialValue === void 0 ? void 0 : getInitialValue();
if (initialValue)
input.value = '';
filterOptions();
updateClearButtonTabindex();
});
input.addEventListener('input', () => {
filterOptions();
updateClearButtonTabindex();
});
input.addEventListener('keydown', (e) => {
if (e.key === 'Tab')
updateClearButtonTabindex();
});
}
function setupListClickHandler(list, selector, callback, preventDefault = false) {
list.addEventListener('click', (e) => {
const clickedOption = e.target.closest(selector);
if (clickedOption) {
if (preventDefault)
e.preventDefault();
callback(clickedOption);
}
});
}
function createCheckboxToggleHandler(updateDisplay) {
return (option) => {
const checkbox = option.querySelector('.tl-checkbox__input');
if (checkbox) {
checkbox.checked = !checkbox.checked;
option.classList.toggle('tl-dropdown__option--selected', checkbox.checked);
updateDisplay();
const changeEvent = new Event('change', { bubbles: true });
checkbox.dispatchEvent(changeEvent);
}
};
}
function setupButtonDropdownEvents(button, toggleDropdown, root, closeDropdown) {
button.addEventListener('click', (e) => {
e.stopPropagation();
toggleDropdown();
});
setupClickOutside(root, closeDropdown);
}
export function tlDropdownSingleScriptDemo(menuId) {
const list = document.getElementById(menuId);
if (!list)
return;
const root = list.closest('.tl-dropdown');
const button = root === null || root === void 0 ? void 0 : root.querySelector('.tl-dropdown__button');
const textDisplay = root === null || root === void 0 ? void 0 : root.querySelector('.tl-dropdown__text');
if (!root || !button)
return;
setupOptionTabindex(list);
const toggleDropdown = createToggleDropdown(button);
const closeDropdown = createCloseDropdown(button);
const selectOption = (selectedOption) => {
var _a;
list.querySelectorAll('.tl-dropdown__option').forEach((option) => {
option.classList.remove('tl-dropdown__option--selected');
});
selectedOption.classList.add('tl-dropdown__option--selected');
if (textDisplay)
textDisplay.textContent = ((_a = selectedOption.textContent) === null || _a === void 0 ? void 0 : _a.trim()) || '';
closeDropdown();
button.focus();
};
setupButtonDropdownEvents(button, toggleDropdown, root, closeDropdown);
setupListClickHandler(list, '.tl-dropdown__option:not(.tl-dropdown__option--disabled)', selectOption);
list.addEventListener('keydown', (e) => handleKeyboardSelection(e, '.tl-dropdown__option:not(.tl-dropdown__option--disabled)', selectOption));
}
export function tlDropdownMultiScriptDemo(menuId) {
const list = document.getElementById(menuId);
if (!list)
return;
const root = list.closest('.tl-dropdown');
const button = root === null || root === void 0 ? void 0 : root.querySelector('.tl-dropdown__button');
const textDisplay = root === null || root === void 0 ? void 0 : root.querySelector('.tl-dropdown__text');
if (!root || !button)
return;
setupOptionTabindex(list, '.tl-dropdown__option', true);
const toggleDropdown = createToggleDropdown(button);
const closeDropdown = createCloseDropdown(button);
const updateDisplay = () => {
if (textDisplay)
textDisplay.textContent = getSelectedCheckboxLabels(list);
};
const handleOptionToggle = createCheckboxToggleHandler(updateDisplay);
setupButtonDropdownEvents(button, toggleDropdown, root, closeDropdown);
setupListClickHandler(list, '.tl-dropdown__option:not(.tl-dropdown__option--disabled)', handleOptionToggle, true);
list.addEventListener('keydown', (e) => handleKeyboardSelection(e, '.tl-dropdown__option:not(.tl-dropdown__option--disabled)', handleOptionToggle));
}
export function tlDropdownFilterSingleScriptDemo(listId, inputId) {
const list = document.getElementById(listId);
const input = document.getElementById(inputId);
if (!list || !input)
return;
const root = list.closest('.tl-dropdown');
const inputWrapper = input.parentElement;
const clearButton = inputWrapper === null || inputWrapper === void 0 ? void 0 : inputWrapper.querySelector('.tl-dropdown__input-clear');
const noResultMessage = list.querySelector('.tl-dropdown__option--no-result');
const options = Array.from(list.querySelectorAll('.tl-dropdown__option:not(.tl-dropdown__option--no-result)'));
setupOptionTabindex(list, '.tl-dropdown__option:not(.tl-dropdown__option--no-result)');
if (noResultMessage)
noResultMessage.setAttribute('tabindex', '-1');
let selectedValue = '';
const openDropdown = () => input.setAttribute('aria-expanded', 'true');
const closeDropdown = createCloseDropdown(input);
const updateClearButtonTabindex = createUpdateClearButtonTabindex(input, clearButton);
const filterOptions = () => {
const searchQuery = input.value.toLowerCase().trim();
let visibleCount = 0;
options.forEach((option) => {
var _a;
const optionText = ((_a = option.textContent) === null || _a === void 0 ? void 0 : _a.trim()) || '';
const isVisible = !searchQuery || optionText.toLowerCase().includes(searchQuery);
option.style.display = isVisible ? '' : 'none';
if (isVisible)
visibleCount++;
});
const showNoResults = !!searchQuery && visibleCount === 0;
if (noResultMessage) {
noResultMessage.style.display = showNoResults ? '' : 'none';
}
};
const selectOption = (selectedOption) => {
var _a;
options.forEach((option) => {
option.classList.remove('tl-dropdown__option--selected');
});
selectedOption.classList.add('tl-dropdown__option--selected');
selectedValue = ((_a = selectedOption.textContent) === null || _a === void 0 ? void 0 : _a.trim()) || '';
input.value = selectedValue;
input.blur();
};
const handleClearButton = () => {
selectedValue = '';
input.value = '';
input.focus();
filterOptions();
updateClearButtonTabindex();
};
setupClearButton(clearButton, handleClearButton);
setupInputWrapperToggle(inputWrapper, input, openDropdown, closeDropdown, filterOptions);
setupInputEvents(input, openDropdown, filterOptions, updateClearButtonTabindex, () => selectedValue);
setupListClickHandler(list, '.tl-dropdown__option:not(.tl-dropdown__option--no-result):not(.tl-dropdown__option--disabled)', selectOption, true);
root === null || root === void 0 ? void 0 : root.addEventListener('focusout', (e) => {
setTimeout(() => {
const newFocus = e.relatedTarget || document.activeElement;
const isClearButton = clearButton && newFocus === clearButton;
if (!root.contains(newFocus) && !isClearButton) {
closeDropdown();
if (selectedValue)
input.value = selectedValue;
}
}, 20);
});
filterOptions();
updateClearButtonTabindex();
}
export function tlDropdownFilterMultiScriptDemo(listId, inputId) {
const list = document.getElementById(listId);
const input = document.getElementById(inputId);
if (!list || !input)
return;
const root = list.closest('.tl-dropdown');
const inputWrapper = input.parentElement;
const clearButton = inputWrapper === null || inputWrapper === void 0 ? void 0 : inputWrapper.querySelector('.tl-dropdown__input-clear');
const options = Array.from(list.querySelectorAll('.tl-dropdown__option'));
setupOptionTabindex(list, '.tl-dropdown__option', true);
const openDropdown = () => input.setAttribute('aria-expanded', 'true');
const closeDropdown = createCloseDropdown(input);
const updateClearButtonTabindex = createUpdateClearButtonTabindex(input, clearButton);
const getSelectedValues = () => getSelectedCheckboxLabels(list);
const filterOptions = () => {
const searchQuery = input.value.toLowerCase().trim();
options.forEach((option) => {
var _a;
const optionText = ((_a = option.textContent) === null || _a === void 0 ? void 0 : _a.trim()) || '';
const isVisible = !searchQuery || optionText.toLowerCase().includes(searchQuery);
option.style.display = isVisible ? '' : 'none';
});
};
const updateDisplay = () => {
input.value = getSelectedValues();
updateClearButtonTabindex();
};
const handleClearButton = () => {
list.querySelectorAll('.tl-checkbox__input:checked').forEach((cb) => {
var _a;
cb.checked = false;
(_a = cb.closest('.tl-dropdown__option')) === null || _a === void 0 ? void 0 : _a.classList.remove('tl-dropdown__option--selected');
});
input.value = '';
input.focus();
filterOptions();
updateClearButtonTabindex();
};
const handleOptionToggle = createCheckboxToggleHandler(updateDisplay);
setupClearButton(clearButton, handleClearButton);
setupInputWrapperToggle(inputWrapper, input, openDropdown, closeDropdown, filterOptions);
setupInputEvents(input, openDropdown, filterOptions, updateClearButtonTabindex, getSelectedValues);
setupListClickHandler(list, '.tl-dropdown__option:not(.tl-dropdown__option--disabled)', handleOptionToggle, true);
list.addEventListener('keydown', (e) => handleKeyboardSelection(e, '.tl-dropdown__option:not(.tl-dropdown__option--disabled)', handleOptionToggle));
root === null || root === void 0 ? void 0 : root.addEventListener('focusout', (e) => {
setTimeout(() => {
const newFocus = e.relatedTarget || document.activeElement;
const isClearButton = clearButton && newFocus === clearButton;
if (!root.contains(newFocus) && !isClearButton) {
closeDropdown();
input.value = getSelectedValues();
}
}, 20);
});
filterOptions();
updateClearButtonTabindex();
}