Skip to content

Commit

Permalink
Fix Autosuggest remaining highlights
Browse files Browse the repository at this point in the history
  • Loading branch information
felixhabib committed Sep 13, 2024
1 parent f554c4f commit f2c9f48
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 24 deletions.
13 changes: 13 additions & 0 deletions .changeset/forty-coins-wait.md
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
Column,
Columns,
TextField,
Inline,
} from '../';
import { IconHelp, IconLanguage } from '../icons';
import { highlightSuggestions } from './Autosuggest';
Expand Down Expand Up @@ -474,11 +473,12 @@ const docs: ComponentDocs = {
each suggestion.
</Text>
),
Example: ({ id, setDefaultState, setState, getState }) =>
source(
Example: ({ id, setDefaultState, setState, getState }) => {
const suggestion = 'Apples and Bananas';

return source(
<>
{setDefaultState('textfield', 'App')}
{setDefaultState('suggestion', 'Apples')}

<Stack space="large">
<TextField
Expand All @@ -494,32 +494,32 @@ const docs: ComponentDocs = {
<Text size="small" tone="secondary">
Highlight <Strong>{highlightType}</Strong>
</Text>
<Inline space="none">
<Text>
{parseHighlights(
getState('suggestion'),
suggestion,
highlightSuggestions(
getState('suggestion'),
suggestion,
getState('textfield'),
highlightType === 'matching'
? 'matching'
: 'remaining',
).map(({ start, end }) => [start, end]),
).map((part, index) => (
<Text
key={index}
weight={part.highlight ? 'strong' : 'regular'}
>
{part.text}
</Text>
))}
</Inline>
).map((part, index) =>
part.highlight ? (
<Strong key={index}>{part.text}</Strong>
) : (
part.text
),
)}
</Text>
</Stack>
</Column>
))}
</Columns>
</Stack>
</>,
),
);
},
code: false,
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import {
type AutosuggestTranslations,
autosuggest,
} from '../../translations/en';
import { reverseMatches } from './reverseMatches';

import * as styles from './Autosuggest.css';

Expand Down Expand Up @@ -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 <Value>(
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
});
});
Original file line number Diff line number Diff line change
@@ -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;
}

0 comments on commit f2c9f48

Please sign in to comment.