UNPKG

@thisismanta/react-playbook

Version:

**Playbook** is a UI library made for listing React components.

101 lines (100 loc) 3.18 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const lodash_1 = require("lodash"); class FuzzySearch { constructor(haystack = [], keys = [], options = {}) { this.haystack = haystack; this.keys = keys; this.options = Object.assign({ caseSensitive: false, sort: false, }, options); } search(query = '') { query = query.trim(); if (!this.options.caseSensitive) { query = query.toLocaleLowerCase(); } if (query === '') { return this.haystack; } const results = []; for (const item of this.haystack) { if (this.keys.length === 0) { const score = this.isMatch(String(item), query); if (score) { results.push({ item, score }); } } else { for (const key of this.keys) { const score = this.isMatch(String((0, lodash_1.get)(item, key)), query); if (score) { results.push({ item, score }); break; } } } } if (this.options.sort) { results.sort((a, b) => a.score - b.score); } return results.map(result => result.item); } isMatch(item, query) { if (!this.options.caseSensitive) { item = item.toLocaleLowerCase(); } const indexes = this.nearestIndexesFor(item, query); if (indexes === false) { return false; } if (item === query) { return 1; } if (indexes.length > 1) { return 2 + (indexes[indexes.length - 1] - indexes[0]); } return 2 + indexes[0]; } nearestIndexesFor(item, query) { const letters = query.split(''); const indexes = this.indexesOfFirstLetter(item, query) .map((startingIndex) => { let index = startingIndex + 1; const results = [startingIndex]; for (let i = 1; i < letters.length; i++) { const letter = letters[i]; index = item.indexOf(letter, index); if (index === -1) { return []; } results.push(index); index++; } return results; }) .filter(letterIndexes => letterIndexes.length > 0); if (indexes.length === 0) { return false; } return indexes.sort((a, b) => { if (a.length === 1) { return a[0] - b[0]; } return (a[a.length - 1] - a[0]) - (b[b.length - 1] - b[0]); })[0]; } indexesOfFirstLetter(item, query) { const match = query[0]; return item.split('') .map((letter, index) => { if (letter !== match) { return null; } return index; }) .filter((index) => typeof index === 'number'); } } exports.default = FuzzySearch;