Skip to content

Commit 040563e

Browse files
authored
Merge 4de8a7d into be8265e
2 parents be8265e + 4de8a7d commit 040563e

File tree

5 files changed

+622
-430
lines changed

5 files changed

+622
-430
lines changed

.changeset/early-colts-sneeze.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@navikt/ds-react": patch
3+
---
4+
5+
Autocomplete in combobox will not change formatting of the letters while being typed, but will use the casing of the autocompleted word when selecting the option.

@navikt/core/react/src/form/combobox/FilteredOptions/filteredOptionsContext.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,7 @@ export const FilteredOptionsProvider = ({ children, value: props }) => {
9595
shouldAutocomplete &&
9696
normalizeText(searchTerm) !== "" &&
9797
(previousSearchTerm?.length || 0) < searchTerm.length &&
98-
filteredOptions.length > 0 &&
99-
!isValueInList(searchTerm, filteredOptions)
98+
filteredOptions.length > 0
10099
) {
101100
setValue(
102101
`${searchTerm}${filteredOptions[0].substring(searchTerm.length)}`

@navikt/core/react/src/form/combobox/Input/Input.tsx

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
3131
allowNewValues,
3232
currentOption,
3333
filteredOptions,
34+
isValueNew,
3435
toggleIsListOpen,
3536
isListOpen,
3637
filteredOptionsIndex,
@@ -46,29 +47,43 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
4647

4748
const onEnter = useCallback(
4849
(event: React.KeyboardEvent) => {
50+
const isTextInSelectedOptions = (text: string) => {
51+
return selectedOptions.find(
52+
(item) => item.toLocaleLowerCase() === text.toLocaleLowerCase()
53+
);
54+
};
55+
4956
if (currentOption) {
5057
event.preventDefault();
5158
// Selecting a value from the dropdown / FilteredOptions
5259
toggleOption(currentOption, event);
53-
if (!isMultiSelect && !selectedOptions.includes(currentOption))
60+
if (!isMultiSelect && !isTextInSelectedOptions(currentOption))
5461
toggleIsListOpen(false);
55-
} else if (shouldAutocomplete && selectedOptions.includes(value)) {
62+
} else if (shouldAutocomplete && isTextInSelectedOptions(value)) {
5663
event.preventDefault();
5764
// Trying to set the same value that is already set, so just clearing the input
5865
clearInput(event);
5966
} else if ((allowNewValues || shouldAutocomplete) && value !== "") {
6067
event.preventDefault();
6168
// Autocompleting or adding a new value
62-
toggleOption(value, event);
63-
if (!isMultiSelect && !selectedOptions.includes(value))
69+
const selectedValue =
70+
allowNewValues && isValueNew ? value : filteredOptions[0];
71+
toggleOption(selectedValue, event);
72+
if (
73+
!isMultiSelect &&
74+
!isTextInSelectedOptions(filteredOptions[0] || selectedValue)
75+
) {
6476
toggleIsListOpen(false);
77+
}
6578
}
6679
},
6780
[
6881
allowNewValues,
6982
clearInput,
7083
currentOption,
84+
filteredOptions,
7185
isMultiSelect,
86+
isValueNew,
7287
selectedOptions,
7388
shouldAutocomplete,
7489
toggleIsListOpen,

@navikt/core/react/src/form/combobox/combobox.stories.tsx

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,50 @@ export const TestThatCallbacksOnlyFireWhenExpected: StoryObj<{
467467
},
468468
};
469469

470+
export const TestCasingWhenAutoCompleting = {
471+
args: {
472+
onChange: jest.fn(),
473+
onClear: jest.fn(),
474+
onToggleSelected: jest.fn(),
475+
},
476+
render: (props) => {
477+
return (
478+
<UNSAFE_Combobox
479+
options={["Camel Case", "lowercase", "UPPERCASE"]}
480+
label="Liker du best store eller små bokstaver?"
481+
shouldAutocomplete
482+
allowNewValues
483+
{...props}
484+
/>
485+
);
486+
},
487+
play: async ({ canvasElement }) => {
488+
const canvas = within(canvasElement);
489+
const input = canvas.getByRole<HTMLInputElement>("combobox");
490+
491+
// With exisiting option
492+
userEvent.click(input);
493+
await userEvent.type(input, "cAmEl CaSe", { delay: 250 });
494+
await sleep(250);
495+
expect(input.value).toBe("cAmEl CaSe");
496+
await userEvent.type(input, "{Enter}");
497+
await sleep(250);
498+
const chips = canvas.getAllByRole("list")[0];
499+
const selectedUpperCaseChip = within(chips).getAllByRole("listitem")[0];
500+
expect(selectedUpperCaseChip).toHaveTextContent("Camel Case"); // A weird issue is preventing the accessible name from being used in the test, even if it works in VoiceOver
501+
502+
// With custom option
503+
userEvent.click(input);
504+
await userEvent.type(input, "cAmEl{Backspace}", { delay: 250 });
505+
await sleep(250);
506+
expect(input.value).toBe("cAmEl");
507+
await userEvent.type(input, "{Enter}");
508+
await sleep(250);
509+
const selectedNewValueChip = within(chips).getAllByRole("listitem")[0];
510+
expect(selectedNewValueChip).toHaveTextContent("cAmEl"); // A weird issue is preventing the accessible name from being used in the test, even if it works in VoiceOver
511+
},
512+
};
513+
470514
export const TestHoverAndFocusSwitching: StoryObject = {
471515
render: () => {
472516
return (

0 commit comments

Comments
 (0)