From f2c9f48d27ce4f61d0cfe17fbe1129c5d75ba1eb Mon Sep 17 00:00:00 2001 From: Felix Habib Date: Fri, 13 Sep 2024 13:24:39 +1000 Subject: [PATCH] Fix `Autosuggest` remaining highlights --- .changeset/forty-coins-wait.md | 13 +++++ .../Autosuggest/Autosuggest.docs.tsx | 34 +++++------ .../components/Autosuggest/Autosuggest.tsx | 13 ++--- .../Autosuggest/reverseMatches.test.ts | 58 +++++++++++++++++++ .../components/Autosuggest/reverseMatches.ts | 22 +++++++ 5 files changed, 116 insertions(+), 24 deletions(-) create mode 100644 .changeset/forty-coins-wait.md create mode 100644 packages/braid-design-system/src/lib/components/Autosuggest/reverseMatches.test.ts create mode 100644 packages/braid-design-system/src/lib/components/Autosuggest/reverseMatches.ts diff --git a/.changeset/forty-coins-wait.md b/.changeset/forty-coins-wait.md new file mode 100644 index 00000000000..25a0250e540 --- /dev/null +++ b/.changeset/forty-coins-wait.md @@ -0,0 +1,13 @@ +--- +'braid-design-system': patch +--- + +--- +updated: + - Autosuggest +--- + +**Autosuggest**: Improve handing of `suggestionHighlight` prop when set to `remaining` + +Fixes a bug in `Autosuggest` when using `suggestionHighlight` prop set to `remaining`. +If the input contained multiple words, the highlighted portion would be appended to the end of matching suggestions. diff --git a/packages/braid-design-system/src/lib/components/Autosuggest/Autosuggest.docs.tsx b/packages/braid-design-system/src/lib/components/Autosuggest/Autosuggest.docs.tsx index 8d5be7a03ff..29b976fe6af 100644 --- a/packages/braid-design-system/src/lib/components/Autosuggest/Autosuggest.docs.tsx +++ b/packages/braid-design-system/src/lib/components/Autosuggest/Autosuggest.docs.tsx @@ -14,7 +14,6 @@ import { Column, Columns, TextField, - Inline, } from '../'; import { IconHelp, IconLanguage } from '../icons'; import { highlightSuggestions } from './Autosuggest'; @@ -474,11 +473,12 @@ const docs: ComponentDocs = { each suggestion. ), - Example: ({ id, setDefaultState, setState, getState }) => - source( + Example: ({ id, setDefaultState, setState, getState }) => { + const suggestion = 'Apples and Bananas'; + + return source( <> {setDefaultState('textfield', 'App')} - {setDefaultState('suggestion', 'Apples')} Highlight {highlightType} - + {parseHighlights( - getState('suggestion'), + suggestion, highlightSuggestions( - getState('suggestion'), + suggestion, getState('textfield'), highlightType === 'matching' ? 'matching' : 'remaining', ).map(({ start, end }) => [start, end]), - ).map((part, index) => ( - - {part.text} - - ))} - + ).map((part, index) => + part.highlight ? ( + {part.text} + ) : ( + part.text + ), + )} + ))} , - ), + ); + }, code: false, }, diff --git a/packages/braid-design-system/src/lib/components/Autosuggest/Autosuggest.tsx b/packages/braid-design-system/src/lib/components/Autosuggest/Autosuggest.tsx index 96fe31f5713..e36517150e4 100644 --- a/packages/braid-design-system/src/lib/components/Autosuggest/Autosuggest.tsx +++ b/packages/braid-design-system/src/lib/components/Autosuggest/Autosuggest.tsx @@ -44,6 +44,7 @@ import { type AutosuggestTranslations, autosuggest, } from '../../translations/en'; +import { reverseMatches } from './reverseMatches'; import * as styles from './Autosuggest.css'; @@ -346,14 +347,12 @@ export function highlightSuggestions( value: string, variant: HighlightOptions = 'matching', ): SuggestionMatch { - const matches = matchHighlights(suggestion, value); + const matches = + variant === 'matching' + ? matchHighlights(suggestion, value) + : reverseMatches(suggestion, matchHighlights(suggestion, value)); - const formattedMatches = - variant === 'remaining' - ? matches.map(([_, end]) => ({ start: end, end: suggestion.length })) - : matches.map(([start, end]) => ({ start, end })); - - return formattedMatches; + return matches.map(([start, end]) => ({ start, end })); } export const Autosuggest = forwardRef(function ( diff --git a/packages/braid-design-system/src/lib/components/Autosuggest/reverseMatches.test.ts b/packages/braid-design-system/src/lib/components/Autosuggest/reverseMatches.test.ts new file mode 100644 index 00000000000..e46b087a02f --- /dev/null +++ b/packages/braid-design-system/src/lib/components/Autosuggest/reverseMatches.test.ts @@ -0,0 +1,58 @@ +import { type Match, reverseMatches } from './reverseMatches'; + +describe('reverseMatches', () => { + it('should return intervals for non-matching parts of the suggestion', () => { + const suggestion = 'Apples etc'; + const matches: Match[] = [ + [2, 4], + [6, 8], + ]; + const expected: Match[] = [ + [0, 2], + [4, 6], + [8, 10], + ]; + + expect(reverseMatches(suggestion, matches)).toEqual(expected); + }); + + it('should handle no matches', () => { + const suggestion = 'Apple'; + const matches: Match[] = []; + const expected: Match[] = [[0, 5]]; + + expect(reverseMatches(suggestion, matches)).toEqual(expected); + }); + + it('should handle matches that cover the entire suggestion', () => { + const suggestion = 'Apple'; + const matches: Match[] = [[0, 5]]; + const expected: Match[] = []; + + expect(reverseMatches(suggestion, matches)).toEqual(expected); + }); + + it('should handle matches at the start of the suggestion', () => { + const suggestion = 'Apple'; + const matches: Match[] = [[0, 2]]; + const expected: Match[] = [[2, 5]]; + + expect(reverseMatches(suggestion, matches)).toEqual(expected); + }); + + it('should handle matches at the end of the suggestion', () => { + const suggestion = 'Apple'; + const matches: Match[] = [[3, 5]]; + const expected: Match[] = [[0, 3]]; + + expect(reverseMatches(suggestion, matches)).toEqual(expected); + }); + + it('should handle matches for a single character suggestion', () => { + const suggestion = 'A'; + const matches: Match[] = [[0, 1]]; + const expected: Match[] = []; + + expect(reverseMatches(suggestion, matches)).toEqual(expected); + }); +}); diff --git a/packages/braid-design-system/src/lib/components/Autosuggest/reverseMatches.ts b/packages/braid-design-system/src/lib/components/Autosuggest/reverseMatches.ts new file mode 100644 index 00000000000..ae233d1a158 --- /dev/null +++ b/packages/braid-design-system/src/lib/components/Autosuggest/reverseMatches.ts @@ -0,0 +1,22 @@ +export type Match = [number, number]; + +export function reverseMatches(suggestion: string, matches: Match[]): Match[] { + const suggestionLength = suggestion.length; + const reversedMatches: Match[] = []; + + let currentStart = 0; + + for (const [start, end] of matches) { + if (currentStart < start) { + reversedMatches.push([currentStart, start]); + } + + currentStart = end; + } + + if (currentStart < suggestionLength) { + reversedMatches.push([currentStart, suggestionLength]); + } + + return reversedMatches; +}