UNPKG

3.71 kBJavaScriptView Raw
1// Copyright (c) Jupyter Development Team.
2// Distributed under the terms of the Modified BSD License.
3import { InputGroup } from '@jupyterlab/ui-components';
4import { StringExt } from '@lumino/algorithm';
5import React, { useEffect, useState } from 'react';
6import { ReactWidget } from './vdom';
7/**
8 * Perform a fuzzy search on a single item.
9 */
10function fuzzySearch(source, query) {
11 // Set up the match score and indices array.
12 let score = Infinity;
13 let indices = null;
14 // The regex for search word boundaries
15 const rgx = /\b\w/g;
16 let continueSearch = true;
17 // Search the source by word boundary.
18 while (continueSearch) {
19 // Find the next word boundary in the source.
20 let rgxMatch = rgx.exec(source);
21 // Break if there is no more source context.
22 if (!rgxMatch) {
23 break;
24 }
25 // Run the string match on the relevant substring.
26 let match = StringExt.matchSumOfDeltas(source, query, rgxMatch.index);
27 // Break if there is no match.
28 if (!match) {
29 break;
30 }
31 // Update the match if the score is better.
32 if (match && match.score <= score) {
33 score = match.score;
34 indices = match.indices;
35 }
36 }
37 // Bail if there was no match.
38 if (!indices || score === Infinity) {
39 return null;
40 }
41 // Handle a split match.
42 return {
43 score,
44 indices
45 };
46}
47export const updateFilterFunction = (value, useFuzzyFilter, caseSensitive) => {
48 return (item) => {
49 if (useFuzzyFilter) {
50 // Run the fuzzy search for the item and query.
51 const query = value.toLowerCase();
52 let score = fuzzySearch(item, query);
53 // Ignore the item if it is not a match.
54 if (!score) {
55 return false;
56 }
57 return true;
58 }
59 if (!caseSensitive) {
60 item = item.toLocaleLowerCase();
61 value = value.toLocaleLowerCase();
62 }
63 const i = item.indexOf(value);
64 if (i === -1) {
65 return false;
66 }
67 return true;
68 };
69};
70export const FilterBox = (props) => {
71 var _a;
72 const [filter, setFilter] = useState((_a = props.initialQuery) !== null && _a !== void 0 ? _a : '');
73 if (props.forceRefresh) {
74 useEffect(() => {
75 props.updateFilter((item) => {
76 return true;
77 });
78 }, []);
79 }
80 useEffect(() => {
81 // If there is an initial search value, pass the parent the initial filter function for that value.
82 if (props.initialQuery !== undefined) {
83 props.updateFilter(updateFilterFunction(props.initialQuery, props.useFuzzyFilter, props.caseSensitive), props.initialQuery);
84 }
85 }, []);
86 /**
87 * Handler for search input changes.
88 */
89 const handleChange = (e) => {
90 const target = e.target;
91 setFilter(target.value);
92 props.updateFilter(updateFilterFunction(target.value, props.useFuzzyFilter, props.caseSensitive), target.value);
93 };
94 return (React.createElement(InputGroup, { type: "text", rightIcon: "ui-components:search", placeholder: props.placeholder, onChange: handleChange, className: "jp-FilterBox", value: filter }));
95};
96/**
97 * A widget which hosts a input textbox to filter on file names.
98 */
99export const FilenameSearcher = (props) => {
100 return ReactWidget.create(React.createElement(FilterBox, { updateFilter: props.updateFilter, useFuzzyFilter: props.useFuzzyFilter, placeholder: props.placeholder, forceRefresh: props.forceRefresh, caseSensitive: props.caseSensitive }));
101};
102//# sourceMappingURL=search.js.map
\No newline at end of file