Skip to content

Commit

Permalink
Add highlight words in the suggestion input (#843)
Browse files Browse the repository at this point in the history
* feat: add highlight words in the suggestion input

* test: fix typo sentence

* refactor: improve component to highlight with empty space
  • Loading branch information
aaschlote committed May 23, 2024
1 parent 1612e2e commit 39f642e
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ describe("SuggestionInput", () => {
const { getByText, getByRole, container } = render(<RemixStub />);

fireEvent.change(getByRole("combobox"), { target: { value: "Berlin" } });
await waitFor(() => getByText("Berlin Brandenburg Flughafen (BER)"));
fireEvent.click(getByText("Berlin Brandenburg Flughafen (BER)"));
await waitFor(() => getByText("Brandenburg Flughafen (BER)"));
fireEvent.click(getByText("Brandenburg Flughafen (BER)"));
expect(mockedValidate).toHaveBeenCalledTimes(1);
await waitFor(() => {
expect(
Expand Down Expand Up @@ -136,8 +136,8 @@ describe("SuggestionInput", () => {
);

fireEvent.change(getByRole("combobox"), { target: { value: "Berlin" } });
await waitFor(() => getByText("Berlin Brandenburg Flughafen (BER)"));
fireEvent.click(getByText("Berlin Brandenburg Flughafen (BER)"));
await waitFor(() => getByText("Brandenburg Flughafen (BER)"));
fireEvent.click(getByText("Brandenburg Flughafen (BER)"));

await waitFor(() => {
expect(
Expand Down Expand Up @@ -181,8 +181,8 @@ describe("SuggestionInput", () => {
).not.toBeInTheDocument();

fireEvent.change(getByRole("combobox"), { target: { value: "Berlin" } });
await waitFor(() => getByText("Berlin Brandenburg Flughafen (BER)"));
fireEvent.click(getByText("Berlin Brandenburg Flughafen (BER)"));
await waitFor(() => getByText("Brandenburg Flughafen (BER)"));
fireEvent.click(getByText("Brandenburg Flughafen (BER)"));

await waitFor(() =>
expect(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,65 @@
import { FormatOptionLabelMeta } from "react-select";
import { DataListOptions } from "../SuggestionInput";

function splitHighlightWord(
text: string | undefined,
matchWord: string,
): string[] {
if (typeof text === "undefined") {
return [];
}

return text.split(new RegExp(`(${matchWord})`, "gi"));
}

const renderHighlightText = (
wordParts: string[],
matchWord: string,
testId: string,
) => {
return wordParts.map((wordPart, index) =>
wordPart.toLowerCase() === matchWord.toLowerCase() ? (
<strong data-testid={testId} key={`${wordPart}-${index}`}>
{wordPart}
</strong>
) : (
wordPart
),
);
};

const FormatOptionLabel = (
{ label, subDescription }: DataListOptions,
{ context }: FormatOptionLabelMeta<DataListOptions>,
{ context, inputValue }: FormatOptionLabelMeta<DataListOptions>,
) => {
if (context === "menu") {
return (
<div style={{ flex: "10" }}>
<span data-testid="suggestion-input-menu-item">{label}</span>
<div>
<span className="primary">{subDescription}</span>
</div>
</div>
);
if (context === "value") {
return <span className="focus:text-blue-100">{label}</span>;
}

return <span className="focus:text-blue-100">{label}</span>;
const inputWithoutSpace = inputValue.trim();

const labelParts = splitHighlightWord(label, inputWithoutSpace);
const subDescriptionParts = splitHighlightWord(
subDescription,
inputWithoutSpace,
);

return (
<div data-testid="suggestion-input-menu-item" style={{ flex: "10" }}>
{renderHighlightText(
labelParts,
inputWithoutSpace,
"suggestion-item-label-highlight",
)}
<div className="primary">
{renderHighlightText(
subDescriptionParts,
inputWithoutSpace,
"suggestion-item-subDescription-highlight",
)}
</div>
</div>
);
};

export default FormatOptionLabel;
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { render } from "@testing-library/react";
import FormatOptionLabel from "../FormatOptionLabel";

describe("FormatOptionLabel", () => {
it("it should render the label if the context is a value", () => {
const dataListOption = [{ label: "Paris", value: " any value" }];

const { getByText } = render(
FormatOptionLabel(dataListOption[0], {
context: "value",
inputValue: "Paris",
selectValue: dataListOption,
}),
);

expect(getByText(dataListOption[0].label)).toBeInTheDocument();
});

it("it should render the label and the subDescription without highlight if the context is a menu", () => {
const dataListOption = [
{ label: "Paris", subDescription: "Paris, France", value: " any value" },
];

const { queryByTestId } = render(
FormatOptionLabel(dataListOption[0], {
context: "menu",
inputValue: "any text",
selectValue: dataListOption,
}),
);

expect(
queryByTestId("suggestion-item-label-highlight"),
).not.toBeInTheDocument();

expect(
queryByTestId("suggestion-item-subDescription-highlight"),
).not.toBeInTheDocument();
});

it("it should render the label and the subDescription with highlight if the context is a menu", () => {
const dataListOption = [
{
label: "Paris Charles de Gaulle",
subDescription: "Paris, France",
value: " any value",
},
];

const mockInputValue = "Paris";

const { queryByTestId } = render(
FormatOptionLabel(dataListOption[0], {
context: "menu",
inputValue: mockInputValue,
selectValue: dataListOption,
}),
);

expect(
queryByTestId("suggestion-item-label-highlight"),
).toBeInTheDocument();
expect(queryByTestId("suggestion-item-label-highlight")?.innerHTML).toBe(
mockInputValue,
);

expect(
queryByTestId("suggestion-item-subDescription-highlight"),
).toBeInTheDocument();
expect(
queryByTestId("suggestion-item-subDescription-highlight")?.innerHTML,
).toBe(mockInputValue);
});

it("it should render the label and the subDescription with highlight if the context is a menu even with empty space", () => {
const dataListOption = [
{
label: "Paris Charles de Gaulle",
subDescription: "Paris, France",
value: " any value",
},
];

const mockInputValue = "Paris";
const emptySpace = " ";

const { queryByTestId } = render(
FormatOptionLabel(dataListOption[0], {
context: "menu",
inputValue: `${mockInputValue}${emptySpace}`,
selectValue: dataListOption,
}),
);

expect(
queryByTestId("suggestion-item-label-highlight"),
).toBeInTheDocument();
expect(queryByTestId("suggestion-item-label-highlight")?.innerHTML).toBe(
mockInputValue,
);

expect(
queryByTestId("suggestion-item-subDescription-highlight"),
).toBeInTheDocument();
expect(
queryByTestId("suggestion-item-subDescription-highlight")?.innerHTML,
).toBe(mockInputValue);
});
});

0 comments on commit 39f642e

Please sign in to comment.