Release 2.8.0
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
(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);
|
||||
}());
|
||||
Reference in New Issue
Block a user