Skip to content

Commit

Permalink
Merge af2deeb into 627f9f7
Browse files Browse the repository at this point in the history
  • Loading branch information
it-vegard authored Aug 25, 2023
2 parents 627f9f7 + af2deeb commit 45efce0
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 4 deletions.
6 changes: 6 additions & 0 deletions .changeset/tasty-llamas-talk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@navikt/ds-react": patch
"@navikt/ds-css": patch
---

Hovering over combobox dropdown will move selection/focus in the list, so we don't end up with a split focus, and reversely when moving focus while hovering
8 changes: 4 additions & 4 deletions @navikt/core/css/form/combobox.css
Original file line number Diff line number Diff line change
Expand Up @@ -256,15 +256,15 @@
}

.navds-combobox__list-item--focus,
.navds-combobox__list-item:hover {
.navds-combobox__list--with-hover .navds-combobox__list-item:hover {
background-color: var(--ac-combobox-list-item-hover-bg, var(--a-surface-hover));
cursor: pointer;
border-left: 4px solid var(--ac-combobox-list-item-hover-border-left, var(--a-border-strong));
padding-left: calc(var(--a-spacing-3) - 4px);
}

.navds-form-field--small .navds-combobox__list-item--focus,
.navds-form-field--small .navds-combobox__list-item:hover {
.navds-combobox__list--with-hover .navds-form-field--small .navds-combobox__list-item:hover {
padding-left: calc(var(--a-spacing-2) - 4px);
}

Expand All @@ -277,7 +277,7 @@
}

.navds-combobox__list-item--selected.navds-combobox__list-item--focus,
.navds-combobox__list-item--selected:hover {
.navds-combobox__list--with-hover .navds-combobox__list-item--selected:hover {
background-color: var(--ac-combobox-list-item-selected-hover-bg, var(--a-surface-action-subtle-hover));
border-left: 4px solid var(--ac-combobox-list-item-selected-hover-border-left, var(--a-border-focus));
padding-left: calc(var(--a-spacing-3) - 4px);
Expand All @@ -291,7 +291,7 @@
gap: 0.25rem;
}

.navds-combobox__list-item__new-option:hover {
.navds-combobox__list--with-hover .navds-combobox__list-item__new-option:hover {
border-bottom: 1px solid var(--a-border-divider);
background: var(--a-surface-neutral-subtle-hover);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ const FilteredOptions = () => {
filteredOptions,
filteredOptionsIndex,
filteredOptionsRef,
isMouseLastUsedInputDevice,
setIsMouseLastUsedInputDevice,
isValueNew,
setFilteredOptionsIndex,
toggleIsListOpen,
} = useFilteredOptionsContext();
const { isMultiSelect, selectedOptions, toggleOption } =
Expand All @@ -30,6 +33,7 @@ const FilteredOptions = () => {
ref={filteredOptionsRef}
className={cl("navds-combobox__list", {
"navds-combobox__list--closed": !isListOpen,
"navds-combobox__list--with-hover": isMouseLastUsedInputDevice,
})}
id={`${id}-filtered-options`}
role="listbox"
Expand All @@ -48,6 +52,12 @@ const FilteredOptions = () => {
{isValueNew && allowNewValues && (
<li
tabIndex={-1}
onMouseMove={() => {
if (filteredOptionsIndex !== -1) {
setFilteredOptionsIndex(-1);
setIsMouseLastUsedInputDevice(true);
}
}}
onPointerUp={(event) => {
toggleOption(value, event);
if (!isMultiSelect && !selectedOptions.includes(value))
Expand Down Expand Up @@ -90,6 +100,12 @@ const FilteredOptions = () => {
id={`${id}-option-${option.replace(" ", "-")}`}
key={option}
tabIndex={-1}
onMouseMove={() => {
if (filteredOptionsIndex !== index) {
setFilteredOptionsIndex(index);
setIsMouseLastUsedInputDevice(true);
}
}}
onPointerUp={(event) => {
toggleOption(option, event);
if (!isMultiSelect && !selectedOptions.includes(option))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import React, {
useCallback,
useRef,
useLayoutEffect,
SetStateAction,
} from "react";
import cl from "clsx";
import { useCustomOptionsContext } from "../customOptionsContext";
Expand Down Expand Up @@ -35,6 +36,8 @@ type FilteredOptionsContextType = {
isListOpen: boolean;
isLoading?: boolean;
filteredOptions: string[];
isMouseLastUsedInputDevice: boolean;
setIsMouseLastUsedInputDevice: React.Dispatch<SetStateAction<boolean>>;
isValueNew: boolean;
toggleIsListOpen: (newState?: boolean) => void;
currentOption: string | null;
Expand Down Expand Up @@ -84,6 +87,9 @@ export const FilteredOptionsProvider = ({ children, value: props }) => {

const previousSearchTerm = usePrevious(searchTerm);

const [isMouseLastUsedInputDevice, setIsMouseLastUsedInputDevice] =
useState(false);

useLayoutEffect(() => {
if (
shouldAutocomplete &&
Expand Down Expand Up @@ -246,6 +252,8 @@ export const FilteredOptionsProvider = ({ children, value: props }) => {
isListOpen,
isLoading,
filteredOptions,
isMouseLastUsedInputDevice,
setIsMouseLastUsedInputDevice,
isValueNew,
toggleIsListOpen,
currentOption,
Expand Down
3 changes: 3 additions & 0 deletions @navikt/core/react/src/form/combobox/Input/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
moveFocusToInput,
moveFocusToEnd,
setFilteredOptionsIndex,
setIsMouseLastUsedInputDevice,
shouldAutocomplete,
} = useFilteredOptionsContext();

Expand Down Expand Up @@ -102,6 +103,7 @@ const Input = forwardRef<HTMLInputElement, InputProps>(

const handleKeyDown = useCallback(
(e) => {
setIsMouseLastUsedInputDevice(false);
if (e.key === "Backspace") {
if (value === "") {
const lastSelectedOption =
Expand Down Expand Up @@ -132,6 +134,7 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
isListOpen,
filteredOptionsIndex,
moveFocusUp,
setIsMouseLastUsedInputDevice,
]
);

Expand Down
49 changes: 49 additions & 0 deletions @navikt/core/react/src/form/combobox/combobox.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -509,3 +509,52 @@ export const TestThatCallbacksOnlyFireWhenExpected = {
expect(args.onChange.mock.calls).toHaveLength(searchWord.length + 1);
},
};

export const TestHoverAndFocusSwitching = {
render: (props) => {
return (
<DemoContainer dataTheme={props.darkMode}>
<UNSAFE_Combobox
options={options}
label="Hva er dine favorittfrukter?"
{...props}
/>
</DemoContainer>
);
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);

await sleep(500);

const getInput = () =>
canvas.getByRole("combobox", {
name: "Hva er dine favorittfrukter?",
});

userEvent.click(getInput());
expect(getInput().getAttribute("aria-expanded")).toEqual("false");
expect(getInput().getAttribute("aria-activedescendant")).toBeNull();

await sleep(250);
userEvent.keyboard("{ArrowDown}");
await sleep(250);
const bananaOption = canvas.getByRole("option", { name: "banana" });
expect(getInput().getAttribute("aria-activedescendant")).toBe(
bananaOption.getAttribute("id")
);

userEvent.keyboard("{ArrowDown}");
await sleep(250);
const appleOption = canvas.getByRole("option", { name: "apple" });
expect(getInput().getAttribute("aria-activedescendant")).toBe(
appleOption.getAttribute("id")
);

userEvent.hover(bananaOption);
await sleep(250);
expect(getInput().getAttribute("aria-activedescendant")).toBe(
bananaOption.getAttribute("id")
);
},
};

0 comments on commit 45efce0

Please sign in to comment.