Skip to content

Instantly share code, notes, and snippets.

@zdk123
Last active August 19, 2022 18:53
Show Gist options
  • Save zdk123/f22b96a6a5d71c642927e7b5954d6c85 to your computer and use it in GitHub Desktop.
Save zdk123/f22b96a6a5d71c642927e7b5954d6c85 to your computer and use it in GitHub Desktop.
import { checkbox, search } from "@jashkenas/inputs"
export function searchCheckbox(
opts,
options = {
value: [],
optionsCheckboxes: undefined, // use this if you want to pass specific options to the checkboxes or the search
optionsSearch: undefined
}
) {
opts = Array.from(opts);
options.value = options.value === undefined ? [] : options.value;
let checkboxes = checkbox(opts, options.optionsCheckboxes || options);
let searchOpts = options.optionsSearch || options;
searchOpts['filter'] = searchFilter2; // override default filter
const search = search(opts, searchOpts);
const btnAll = html`<button class="check">All</button>`;
const btnNone = html`<button class="check">None</button>`;
let selected = new Map(Array.from(options.value).map((d) => [d, true]));
//console.log(selected);
function selectedToArray() {
return Array.from(selected.entries())
.filter(([k, v]) => v)
.map(([k, v]) => k);
}
function changeSome(sel, changeTo) {
for (let o of sel) selected.set(o, changeTo);
}
function selectedFromArray(sel) {
changeSome(opts, false);
changeSome(sel, true);
}
let output = html`<output>`;
const component = html`${search}
${btnAll}
${btnNone}
${output}
${checkboxes}`;
// Update the display whenever the value changes
Object.defineProperty(component, "value", {
get() {
return selectedToArray();
},
set(v) {
selectedFromArray(v);
}
});
btnAll.addEventListener("click", () => {
changeSome(search.value, true);
checkboxes.value = selectedToArray();
component.dispatchEvent(new Event("input", { bubbles: true }));
});
btnNone.addEventListener("click", () => {
changeSome(search.value, false);
checkboxes.value = selectedToArray();
component.dispatchEvent(new Event("input", { bubbles: true }));
});
component.value = selectedToArray();
search.addEventListener("input", () => {
// Hide all the checkboxes that aren't in the searchbox result
console.log(search.value);
for (let check of checkboxes.querySelectorAll("input")) {
if (search.value.includes(opts[+check.value])) {
check.parentElement.style.display = "inline-block";
// auto-select search matches
changeSome([options.value[check.value]], true);
check.checked = true;
} else {
check.parentElement.style.display = "none";
// auto-disselect search non-matches
changeSome([options.value[check.value]], false);
check.checked = false;
}
}
component.dispatchEvent(new Event("input"));
});
checkboxes.addEventListener("input", () => {
component.value = checkboxes.value;
component.dispatchEvent(new Event("input"));
});
return component;
}
function* valuesof(d) {
for (const key in d) {
yield d[key];
}
}
// removes beginning anchor of the default regex filter
function escapeRegExp(text) {
return text.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
}
function termFilter(term) {
let regex = new RegExp(`(?:|[^\\p{L}-])${escapeRegExp(term)}`, "iu");
console.log(regex)
return regex;
}
function searchFilter2(query) {
const filters = `${query}`.split(/\s+/g).filter(t => t).map(termFilter);
return d => {
if (d == null) return false;
if (typeof d === "object") {
out: for (const filter of filters) {
for (const value of valuesof(d)) {
if (filter.test(value)) {
continue out;
}
}
return false;
}
} else {
for (const filter of filters) {
if (!filter.test(d)) {
return false;
}
}
}
return true;
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment