-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Support entities autocomplete for local characters #30399
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
c479fca
e517ba1
1082daa
3ba65cf
f891c4e
4e2d04e
e5b2e28
8f00c3c
c59f1d8
86e233f
146baf2
0c7cbae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,26 @@ | ||
| // Characters that don't decompose via NFD normalization (e.g. Polish ł, Danish ø) | ||
| const NON_DECOMPOSABLE_MAP: Record<string, string> = { | ||
| ł: "l", | ||
| Ł: "L", | ||
| đ: "d", | ||
| Đ: "D", | ||
| ø: "o", | ||
| Ø: "O", | ||
| ħ: "h", | ||
| Ħ: "H", | ||
| ŧ: "t", | ||
| Ŧ: "T", | ||
| ı: "i", | ||
| ß: "ss", | ||
| }; | ||
|
|
||
| const NON_DECOMPOSABLE_RE = new RegExp( | ||
| `[${Object.keys(NON_DECOMPOSABLE_MAP).join("")}]`, | ||
| "g" | ||
| ); | ||
|
|
||
| export const stripDiacritics = (str: string) => | ||
| str.normalize("NFD").replace(/[\u0300-\u036F]/g, ""); | ||
| str | ||
| .replace(NON_DECOMPOSABLE_RE, (ch) => NON_DECOMPOSABLE_MAP[ch]) | ||
| .normalize("NFD") | ||
| .replace(/[\u0300-\u036F]/g, ""); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,23 +1,45 @@ | ||
| import type { | ||
| Expression, | ||
| FuseGetFunction, | ||
| FuseIndex, | ||
| FuseOptionKey, | ||
| FuseResult, | ||
| IFuseOptions, | ||
| } from "fuse.js"; | ||
| import Fuse from "fuse.js"; | ||
| import { stripDiacritics } from "../common/string/strip-diacritics"; | ||
|
|
||
| export interface FuseWeightedKey { | ||
| name: string | string[]; | ||
| weight: number; | ||
| } | ||
|
|
||
| /** | ||
| * Custom getFn that normalizes non-decomposable diacritics (e.g. ł→l, ø→o) | ||
| * before Fuse.js indexes values. Fuse's built-in ignoreDiacritics only handles | ||
| * characters that decompose via NFD, missing characters like Polish ł. | ||
| */ | ||
| export const normalizingGetFn: FuseGetFunction<any> = ( | ||
| obj: any, | ||
| path: string | string[] | ||
| ) => { | ||
| const value = Fuse.config.getFn(obj, path); | ||
| if (typeof value === "string") { | ||
| return stripDiacritics(value); | ||
| } | ||
| if (Array.isArray(value)) { | ||
| return value.map((v) => (typeof v === "string" ? stripDiacritics(v) : v)); | ||
| } | ||
| return value; | ||
| }; | ||
|
|
||
| const DEFAULT_OPTIONS: IFuseOptions<any> = { | ||
| ignoreDiacritics: true, | ||
| isCaseSensitive: false, | ||
| threshold: 0.3, | ||
| minMatchCharLength: 2, | ||
| ignoreLocation: true, // don't care where the pattern is | ||
| getFn: normalizingGetFn, | ||
| }; | ||
|
|
||
| const DEFAULT_MIN_CHAR_LENGTH = 2; | ||
|
|
@@ -37,6 +59,10 @@ function searchTerm<T>( | |
| options?: IFuseOptions<T>, | ||
| minMatchCharLength?: number | ||
| ) { | ||
| // Normalize non-decomposable diacritics in search terms to match getFn normalization | ||
| const normalizedSearch = | ||
| typeof search === "string" ? stripDiacritics(search) : search; | ||
|
|
||
|
Comment on lines
+62
to
+65
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function is not exported and only used in this file. Other callers already normalize terms before passing them in so the second strip is not useful.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it is needed, for example In general it's not too DRY, IMO we can solve it in two phases
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Applied other suggestions |
||
| const fuse = new Fuse<T>( | ||
| items, | ||
| { | ||
|
|
@@ -51,7 +77,7 @@ function searchTerm<T>( | |
| fuseIndex | ||
| ); | ||
|
|
||
| return fuse.search(search); | ||
| return fuse.search(normalizedSearch); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -77,7 +103,8 @@ export function multiTermSearch<T>( | |
| const terms = search | ||
| .toLowerCase() | ||
| .split(" ") | ||
| .filter((t) => t.trim()); | ||
| .filter((t) => t.trim()) | ||
| .map((t) => stripDiacritics(t)); | ||
|
|
||
| if (!terms.length) { | ||
| return items; | ||
|
|
@@ -150,7 +177,8 @@ export function multiTermSortedSearch<T>( | |
| const terms = search | ||
| .toLowerCase() | ||
| .split(" ") | ||
| .filter((t) => t.trim()); | ||
| .filter((t) => t.trim()) | ||
| .map((t) => stripDiacritics(t)); | ||
|
|
||
| if (!terms.length) { | ||
| return items; | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.