Mail-DMARC
view release on metacpan or search on metacpan
share/html/js/combo.js view on Meta::CPAN
// A filtering picker for lists too long to scroll: a store can hold thousands
// of domains, and a plain select makes finding one a scrolling exercise.
import { el, clear } from './core.js';
const VISIBLE = 60;
export const combobox = ({ id, placeholder, onSelect }) => {
const input = el('input', {
type: 'text',
role: 'combobox',
id,
class: 'combo-input',
placeholder,
autocomplete: 'off',
spellcheck: 'false',
'aria-expanded': 'false',
'aria-autocomplete': 'list',
'aria-controls': `${id}-list`,
});
const list = el('ul', { id: `${id}-list`, class: 'combo-list', role: 'listbox',
hidden: true });
const node = el('div', { class: 'combo' }, [input, list]);
// items: [{ value, label, note }]. The empty value is the "everything" row.
let items = [];
let matches = [];
let active = -1;
let committed = { value: '', label: placeholder };
const close = () => {
list.hidden = true;
input.setAttribute('aria-expanded', 'false');
input.removeAttribute('aria-activedescendant');
active = -1;
};
const revert = () => {
input.value = committed.value ? committed.label : '';
close();
};
const commit = (item) => {
committed = item;
input.value = item.value ? item.label : '';
close();
onSelect(item.value);
};
const highlight = (index) => {
active = index;
for (const [i, option] of [...list.children].entries()) {
const on = i === index;
option.classList.toggle('active', on);
if (on) {
input.setAttribute('aria-activedescendant', option.id);
option.scrollIntoView({ block: 'nearest' });
}
}
};
// Domains are dotted labels, so a bare substring match buries the obvious
// answer: typing "art" should offer artfulmail.net and theartfarm.com before
// earthlink.net. Rank by where the match lands, keeping the existing order
// inside each rank.
const rank = (label, needle) => {
if (label.startsWith(needle)) return 0;
if (label.includes(`.${needle}`)) return 1;
const at = label.indexOf(needle);
if (at > 0 && !/[a-z0-9]/.test(label[at - 1])) return 1;
return 2;
( run in 1.503 second using v1.01-cache-2.11-cpan-8dfa8b56332 )