JSFiddle - React, Tailwind, and code Playground
by Jason Miller
JavaScript
(async () => {
const {signal, computed, effect} = await import('https://esm.sh/@preact/signals-core');
function computedWithMemo(compute, getKey) {
let lastKey, last;
return computed(() => {
const result = compute();
const key = getKey(result);
if (last !== undefined && key === lastKey) return last;
lastKey = key;
return last = result;
});
}
const search = signal('');
const items = signal([
{id:1, text:'John Doe'},
{id:2, text:'Joan Doe'},
{id:3, text:'Jane Doe'},
{id:4, text:'Bob Dole'},
{id:5, text:'Bob Cat'},
]);
const filtered = computedWithMemo(
() => {
if (!search.value) return items.value;
const pattern = new RegExp('('+search.value.replace(/([.^$[]()])/g, '\\$1')+')', 'i')
return items.value
.filter(item => item.text.match(pattern))
.map(item => ({
...item,
highlight: item.text.replace(pattern, `<b>$1</b>`)
}));
},
(list) => list.reduce((str, item) => str + item.id + item.highlight, ''),
);
const searchField = document.createElement('input');
searchField.type = 'search';
searchField.oninput = (e) => search.value = e.target.value;
const results = document.createElement('ul');
const status = document.createElement('div');
document.body.append(searchField, status, results);
effect(() => {
status.textContent = search.value
? `${filtered.value.length} results for ${search}:`
: `${filtered.value.length} items:`;
results.replaceChildren(...filtered.value.map(item => {
const result = document.createElement('li');
result.innerHTML = item.highlight ?? item.text;
return result;
}));
});
})();