Skip to content

Commit

Permalink
integrate text input into filter for multi select
Browse files Browse the repository at this point in the history
  • Loading branch information
ibolton336 committed Jan 23, 2024
1 parent 66d9800 commit 7835fc7
Showing 1 changed file with 175 additions and 23 deletions.
198 changes: 175 additions & 23 deletions client/src/app/components/FilterToolbar/MultiselectFilterControl.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import * as React from "react";
import {
Badge,
Button,
MenuToggle,
MenuToggleElement,
Select,
SelectGroup,
SelectOption,
SelectOptionProps,
TextInputGroup,
TextInputGroupMain,
TextInputGroupUtilities,
ToolbarChip,
ToolbarFilter,
Tooltip,
Expand All @@ -17,7 +20,7 @@ import {
FilterSelectOptionProps,
} from "./FilterToolbar";
import { css } from "@patternfly/react-styles";
import spacing from "@patternfly/react-styles/css/utilities/Spacing/spacing";
import { TimesIcon } from "@patternfly/react-icons";

import "./select-overrides.css";

Expand Down Expand Up @@ -161,29 +164,178 @@ export const MultiselectFilterControl = <TItem,>({
// });
// };

const toggle = (toggleRef: React.Ref<MenuToggleElement>) => {
return (
<MenuToggle
aria-label={"Multiselect"}
id={`${category.key}-filter-value-select`}
isFullWidth
ref={toggleRef}
onClick={() => {
setIsFilterDropdownOpen(!isFilterDropdownOpen);
}}
isExpanded={isFilterDropdownOpen}
isDisabled={isDisabled || category.selectOptions.length === 0}
>
{category.placeholderText}
{filterValue?.length ? (
<Badge className={spacing.mlSm} isRead>
{filterValue?.length}
</Badge>
) : null}
</MenuToggle>
);
// const toggle = (toggleRef: React.Ref<MenuToggleElement>) => {
// return (
// <MenuToggle
// aria-label={"Multiselect"}
// id={`${category.key}-filter-value-select`}
// isFullWidth
// ref={toggleRef}
// onClick={() => {
// setIsFilterDropdownOpen(!isFilterDropdownOpen);
// }}
// isExpanded={isFilterDropdownOpen}
// isDisabled={isDisabled || category.selectOptions.length === 0}
// variant="typeahead"
// >
// {category.placeholderText}
// {filterValue?.length ? (
// <Badge className={spacing.mlSm} isRead>
// {filterValue?.length}
// </Badge>
// ) : null}
// </MenuToggle>
// );
// };
const [focusedItemIndex, setFocusedItemIndex] = React.useState<number | null>(
null
);
const [selected, setSelected] = React.useState<string>("");
const [activeItem, setActiveItem] = React.useState<string | null>(null);
const textInputRef = React.useRef<HTMLInputElement>();
const [inputValue, setInputValue] = React.useState<string>("");
// const [selectOptions, setSelectOptions] =
// React.useState<SelectOptionProps[]>(initialSelectOptions);

const onSelect = (
_event: React.MouseEvent<Element, MouseEvent> | undefined,
value: string | number | undefined
) => {
// eslint-disable-next-line no-console
console.log("selected", value);

if (value && value !== "no results") {
setInputValue(value as string);
setFilterValue(null);
setSelected(value as string);
}
setIsFilterDropdownOpen(false);
setFocusedItemIndex(null);
setActiveItem(null);
};

const handleMenuArrowKeys = (key: string) => {
if (isFilterDropdownOpen && Array.isArray(selectOptions)) {
let indexToFocus: number = focusedItemIndex ?? -1; // default to -1 if null

if (key === "ArrowUp") {
indexToFocus =
indexToFocus <= 0 ? selectOptions.length - 1 : indexToFocus - 1;
} else if (key === "ArrowDown") {
indexToFocus =
indexToFocus >= selectOptions.length - 1 ? 0 : indexToFocus + 1;
}

// Skip disabled options
while (selectOptions[indexToFocus].isDisabled) {
indexToFocus = key === "ArrowUp" ? indexToFocus - 1 : indexToFocus + 1;
// Handle wrapping around the array
if (indexToFocus < 0) {
indexToFocus = selectOptions.length - 1;
} else if (indexToFocus >= selectOptions.length) {
indexToFocus = 0;
}
}

// Update the focus index and active item
setFocusedItemIndex(indexToFocus);
const focusedItem = selectOptions[indexToFocus];
setActiveItem(`select-typeahead-${focusedItem.value.replace(" ", "-")}`);
}
};

const onInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
const enabledMenuItems = Array.isArray(selectOptions)
? selectOptions.filter((option) => !option.isDisabled)
: [];
const [firstMenuItem] = enabledMenuItems;
const focusedItem = focusedItemIndex
? enabledMenuItems[focusedItemIndex]
: firstMenuItem;

switch (event.key) {
// Select the first available option
case "Enter":
if (isFilterDropdownOpen && focusedItem.value !== "no results") {
setInputValue(String(focusedItem.children));
setFilterValue(null);
setSelected(String(focusedItem.children));
}

setIsFilterDropdownOpen((prevIsOpen) => !prevIsOpen);
setFocusedItemIndex(null);
setActiveItem(null);

break;
case "Tab":
case "Escape":
setIsFilterDropdownOpen(false);
setActiveItem(null);
break;
case "ArrowUp":
case "ArrowDown":
event.preventDefault();
handleMenuArrowKeys(event.key);
break;
}
};

const onTextInputChange = (
_event: React.FormEvent<HTMLInputElement>,
value: string
) => {
setInputValue(value);
setFilterValue([value]);
};

const toggle = (toggleRef: React.Ref<MenuToggleElement>) => (
<MenuToggle
ref={toggleRef}
variant="typeahead"
onClick={() => {
setIsFilterDropdownOpen(!isFilterDropdownOpen);
}}
isExpanded={isFilterDropdownOpen}
isFullWidth
>
<TextInputGroup isPlain>
<TextInputGroupMain
value={inputValue}
onClick={() => {
setIsFilterDropdownOpen(!isFilterDropdownOpen);
}}
onChange={onTextInputChange}
onKeyDown={onInputKeyDown}
id="typeahead-select-input"
autoComplete="off"
innerRef={textInputRef}
placeholder="Select a state"
{...(activeItem && { "aria-activedescendant": activeItem })}
role="combobox"
isExpanded={isFilterDropdownOpen}
aria-controls="select-typeahead-listbox"
/>

<TextInputGroupUtilities>
{!!inputValue && (
<Button
variant="plain"
onClick={() => {
setSelected("");
setInputValue("");
setFilterValue(null);
textInputRef?.current?.focus();
}}
aria-label="Clear input value"
>
<TimesIcon aria-hidden />
</Button>
)}
</TextInputGroupUtilities>
</TextInputGroup>
</MenuToggle>
);

return (
<ToolbarFilter
id={`filter-control-${category.key}`}
Expand Down

0 comments on commit 7835fc7

Please sign in to comment.