Skip to content

Commit

Permalink
feat(combobox): set focus to input on option click
Browse files Browse the repository at this point in the history
  • Loading branch information
gjulivan committed Jan 12, 2024
1 parent 7aa5c1f commit 3b3c4b7
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ exports[`Combo box (Association) renders combobox widget 1`] = `
class="widget-combobox-menu-header widget-combobox-item"
>
<span
class="widget-combobox-icon-container"
class="widget-combobox-menu-header-select-all-button widget-combobox-icon-container"
>
<input
checked=""
Expand Down Expand Up @@ -195,7 +195,7 @@ exports[`Combo box (Association) toggles combobox menu on: input CLICK(focus) /
class="widget-combobox-menu-header widget-combobox-item"
>
<span
class="widget-combobox-icon-container"
class="widget-combobox-menu-header-select-all-button widget-combobox-icon-container"
>
<input
checked=""
Expand Down Expand Up @@ -306,7 +306,7 @@ exports[`Combo box (Association) toggles combobox menu on: input TOGGLE BUTTON 1
class="widget-combobox-menu-header widget-combobox-item"
>
<span
class="widget-combobox-icon-container"
class="widget-combobox-menu-header-select-all-button widget-combobox-icon-container"
>
<input
checked=""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import classNames from "classnames";
import { UseComboboxPropGetters } from "downshift/typings";
import { PropsWithChildren, ReactElement, ReactNode, createElement } from "react";
import { PropsWithChildren, ReactElement, ReactNode, createElement, MouseEvent } from "react";
import { useMenuStyle } from "../hooks/useMenuStyle";
import { NoOptionsPlaceholder } from "./Placeholder";

Expand All @@ -9,8 +9,10 @@ interface ComboboxMenuWrapperProps extends PropsWithChildren, Partial<UseCombobo
isEmpty: boolean;
noOptionsText?: string;
alwaysOpen?: boolean;
highlightedIndex?: number | null;
menuHeaderContent?: ReactNode;
menuFooterContent?: ReactNode;
onOptionClick?: (e: MouseEvent) => void;
}

function PreventMenuCloseEventHandler(e: React.MouseEvent) {
Expand All @@ -19,8 +21,18 @@ function PreventMenuCloseEventHandler(e: React.MouseEvent) {
}

export function ComboboxMenuWrapper(props: ComboboxMenuWrapperProps): ReactElement {
const { children, isOpen, isEmpty, noOptionsText, alwaysOpen, getMenuProps, menuHeaderContent, menuFooterContent } =
props;
const {
children,
isOpen,
isEmpty,
noOptionsText,
alwaysOpen,
getMenuProps,
menuHeaderContent,
menuFooterContent,
highlightedIndex,
onOptionClick
} = props;

const [ref, style] = useMenuStyle<HTMLDivElement>(isOpen);

Expand All @@ -46,7 +58,17 @@ export function ComboboxMenuWrapper(props: ComboboxMenuWrapperProps): ReactEleme
{menuHeaderContent}
</div>
)}
<ul className="widget-combobox-menu-list" {...getMenuProps?.({}, { suppressRefError: true })}>
<ul
className={classNames("widget-combobox-menu-list", {
"widget-combobox-menu-highlighted": (highlightedIndex ?? -1) >= 0
})}
{...getMenuProps?.(
{
onClick: onOptionClick
},
{ suppressRefError: true }
)}
>
{isOpen ? isEmpty ? <NoOptionsPlaceholder>{noOptionsText}</NoOptionsPlaceholder> : children : null}
</ul>
{menuFooterContent && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,6 @@ export function MultiSelection({
<SelectAllButton
value={isOptionsSelected}
id={`${options.inputId}-select-all-button`}
unfocused={highlightedIndex >= 0}
ariaLabel={a11yConfig.ariaLabels.selectAll}
onChange={() => {
if (isOptionsSelected === "all") {
Expand All @@ -165,6 +164,9 @@ export function MultiSelection({
getMenuProps={getMenuProps}
selectedItems={selectedItems}
noOptionsText={options.noOptionsText}
onOptionClick={() => {
inputRef.current?.focus();
}}
/>
</Fragment>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { UseComboboxPropGetters } from "downshift/typings";
import { ReactElement, ReactNode, createElement } from "react";
import { ReactElement, ReactNode, createElement, MouseEvent } from "react";
import { Checkbox } from "../../assets/icons";
import { MultiSelector } from "../../helpers/types";
import { ComboboxMenuWrapper } from "../ComboboxMenuWrapper";
Expand All @@ -15,6 +15,7 @@ interface MultiSelectionMenuProps extends Partial<UseComboboxPropGetters<string>
inputId?: string;
menuHeaderContent?: ReactNode;
menuFooterContent?: ReactNode;
onOptionClick?: (e: MouseEvent) => void;
}

export function MultiSelectionMenu({
Expand All @@ -27,16 +28,19 @@ export function MultiSelectionMenu({
noOptionsText,
inputId,
menuHeaderContent,
menuFooterContent
menuFooterContent,
onOptionClick
}: MultiSelectionMenuProps): ReactElement {
return (
<ComboboxMenuWrapper
isOpen={isOpen}
isEmpty={selectableItems.length <= 0}
getMenuProps={getMenuProps}
noOptionsText={noOptionsText}
highlightedIndex={highlightedIndex}
menuHeaderContent={menuHeaderContent}
menuFooterContent={menuFooterContent}
onOptionClick={onOptionClick}
>
{isOpen &&
selectableItems.map((item, index) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,16 @@ interface SelectAllButtonProps extends Partial<UseComboboxPropGetters<string>> {
id?: string;
ariaLabel?: string;
value: ThreeStateCheckBoxEnum;
unfocused: boolean;
onChange?: () => void;
}

export function SelectAllButton({ id, ariaLabel, value, unfocused, onChange }: SelectAllButtonProps): ReactElement {
export function SelectAllButton({ id, ariaLabel, value, onChange }: SelectAllButtonProps): ReactElement {
return (
<Fragment>
<span
className={classNames(
"widget-combobox-menu-header-select-all-button",
"widget-combobox-icon-container",
{ unfocused }
"widget-combobox-icon-container"
)}
>
<ThreeStateCheckBox value={value} id={id} onChange={onChange} />
Expand Down
12 changes: 2 additions & 10 deletions packages/pluggableWidgets/combobox-web/src/ui/Combobox.scss
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,11 @@ $menu-outer-padding: 10px;
}

&:has(input[type="checkbox"]:hover, :focus, :focus-within)
+ .widget-combobox-menu-list
input[type="checkbox"]:after {
+ .widget-combobox-menu-list:not(.widget-combobox-menu-highlighted)
input[type="checkbox"]:not(:checked):after {
content: "";
border-color: $hover-color;
}

&-select-all-button {
&.unfocused {
.three-state-checkbox {
outline: none;
}
}
}
}

&-footer {
Expand Down

0 comments on commit 3b3c4b7

Please sign in to comment.