112 lines
4.9 KiB
JavaScript
112 lines
4.9 KiB
JavaScript
(function () {
|
|
'use strict';
|
|
|
|
function initIconPicker(root) {
|
|
var select = root.querySelector('select');
|
|
var toggle = root.querySelector('[data-icon-picker-toggle]');
|
|
var menu = root.querySelector('[data-icon-picker-menu]');
|
|
var preview = root.querySelector('[data-icon-picker-preview]');
|
|
var label = root.querySelector('[data-icon-picker-label]');
|
|
var search = root.querySelector('[data-icon-picker-search]');
|
|
var close = root.querySelector('[data-icon-picker-close]');
|
|
var grid = root.querySelector('[data-icon-picker-grid]');
|
|
var empty = root.querySelector('[data-icon-picker-empty]');
|
|
var initialOptions = Array.prototype.slice.call(root.querySelectorAll('[data-icon-picker-option]'));
|
|
|
|
if (!select || !toggle || !menu || !grid) {
|
|
return;
|
|
}
|
|
|
|
function catalogOptions() {
|
|
return Array.prototype.slice.call(select.options).map(function (option) {
|
|
return { value: option.value, label: option.textContent || option.label || option.value };
|
|
});
|
|
}
|
|
|
|
function createOption(option, selectedValue) {
|
|
var button = document.createElement('button');
|
|
button.type = 'button';
|
|
button.className = 'announcement-icon-picker__option';
|
|
button.setAttribute('data-icon-picker-option', '');
|
|
button.setAttribute('data-icon-key', option.value);
|
|
button.setAttribute('data-icon-label', option.label);
|
|
button.setAttribute('aria-pressed', option.value === selectedValue ? 'true' : 'false');
|
|
button.title = option.label;
|
|
button.innerHTML = '<i class="bi bi-' + option.value + '" aria-hidden="true"></i><span class="visually-hidden">' + option.label + '</span>';
|
|
return button;
|
|
}
|
|
|
|
function getOptionLimit() {
|
|
var firstOption = grid.querySelector('[data-icon-picker-option]');
|
|
var gridStyle = window.getComputedStyle(grid);
|
|
var gap = parseFloat(gridStyle.columnGap || gridStyle.gap || '0') || 0;
|
|
var optionWidth = firstOption ? firstOption.getBoundingClientRect().width : 0;
|
|
var columns = optionWidth && grid.clientWidth
|
|
? Math.max(1, Math.floor((grid.clientWidth + gap) / (optionWidth + gap)))
|
|
: 4;
|
|
return columns * 6;
|
|
}
|
|
|
|
function updatePreview() {
|
|
var option = select.options[select.selectedIndex];
|
|
var value = option ? option.value : '';
|
|
if (preview) {
|
|
preview.className = 'announcement-icon-picker__toggle-icon bi bi-' + value;
|
|
}
|
|
if (label) {
|
|
label.textContent = option ? option.textContent : 'Select an icon';
|
|
}
|
|
root.querySelectorAll('[data-icon-picker-option]').forEach(function (optionButton) {
|
|
var selected = optionButton.getAttribute('data-icon-key') === value;
|
|
optionButton.classList.toggle('is-selected', selected);
|
|
optionButton.setAttribute('aria-pressed', selected ? 'true' : 'false');
|
|
});
|
|
}
|
|
|
|
function render(query) {
|
|
var normalizedQuery = String(query || '').trim().toLowerCase();
|
|
var selectedValue = String(select.value || '').trim();
|
|
var options = normalizedQuery
|
|
? catalogOptions().filter(function (option) { return (option.value + ' ' + option.label).toLowerCase().indexOf(normalizedQuery) !== -1; })
|
|
: initialOptions.map(function (option) { return { value: option.getAttribute('data-icon-key') || '', label: option.getAttribute('data-icon-label') || '' }; });
|
|
var visibleOptions = options.slice(0, getOptionLimit());
|
|
grid.innerHTML = '';
|
|
visibleOptions.forEach(function (option) { grid.appendChild(createOption(option, selectedValue)); });
|
|
if (empty) empty.hidden = options.length > 0;
|
|
updatePreview();
|
|
}
|
|
|
|
function closeMenu() {
|
|
menu.hidden = true;
|
|
toggle.setAttribute('aria-expanded', 'false');
|
|
}
|
|
|
|
toggle.addEventListener('click', function (event) {
|
|
event.preventDefault();
|
|
menu.hidden = !menu.hidden;
|
|
toggle.setAttribute('aria-expanded', menu.hidden ? 'false' : 'true');
|
|
if (!menu.hidden) {
|
|
render(search ? search.value : '');
|
|
if (search) search.focus();
|
|
}
|
|
});
|
|
if (close) close.addEventListener('click', function (event) { event.preventDefault(); closeMenu(); });
|
|
grid.addEventListener('click', function (event) {
|
|
var option = event.target.closest ? event.target.closest('[data-icon-picker-option]') : null;
|
|
if (!option) return;
|
|
select.value = option.getAttribute('data-icon-key') || '';
|
|
select.dispatchEvent(new Event('change', { bubbles: true }));
|
|
closeMenu();
|
|
});
|
|
if (search) search.addEventListener('input', function () { render(search.value); });
|
|
select.addEventListener('change', updatePreview);
|
|
document.addEventListener('click', function (event) {
|
|
if (!menu.hidden && !root.contains(event.target)) closeMenu();
|
|
});
|
|
updatePreview();
|
|
}
|
|
|
|
window.PulseIconPicker = { init: initIconPicker };
|
|
document.querySelectorAll('[data-icon-picker]').forEach(initIconPicker);
|
|
}());
|