Fix tab focus state in New select (#7139)

* Fix tab focus state

* Update packages/ui/components/form/selectimproved/components/Select.tsx

* Remove flex import
This commit is contained in:
sean-brydon authored and GitHub committed 2023-02-17 11:15:02 +00:00
1 parent b6016c8f20
commit f77e7476d2
2 files changed
+105 -129

No files matched your search

@@ -1,8 +1,7 @@
import * as Popover from "@radix-ui/react-popover";
import React, { useCallback, useRef, useState } from "react";
import { classNames as cn } from "@calcom/lib";
import { useKeyPress } from "@calcom/lib/hooks/useKeyPress";
import useOnClickOutside from "@calcom/lib/hooks/useOnclickOutside";
import { FiX, FiChevronDown } from "../../../icon";
import Options from "./Options";
@@ -55,41 +54,12 @@ function Select<T extends Option>({
menuIsOpen = false,
classNames,
}: SelectProps<T>) {
const [open, setOpen] = useState<boolean>(menuIsOpen);
const [inputValue, setInputValue] = useState<string>("");
const ref = useRef<HTMLDivElement>(null);
const [open, setOpen] = useState(menuIsOpen);
const searchBoxRef = useRef<HTMLInputElement>(null);
const isMultipleValue = Array.isArray(selectedItems) && isMultiple;
const toggle = useCallback(() => {
if (!isDisabled) {
setOpen(!open);
}
}, [isDisabled, open]);
const closeDropDown = useCallback(() => {
if (open) setOpen(false);
}, [open]);
useOnClickOutside(ref, () => {
closeDropDown();
});
useKeyPress("Escape", undefined, () => {
closeDropDown();
});
const onPressEnterOrSpace = useCallback(
(e: React.KeyboardEvent<HTMLDivElement>) => {
e.preventDefault();
if ((e.code === "Enter" || e.code === "Space") && !isDisabled) {
toggle();
}
},
[isDisabled, toggle]
);
const removeItem = useCallback(
(item: Option) => {
// remove the item from the selected items
@@ -103,6 +73,11 @@ function Select<T extends Option>({
[onChange, selectedItems]
);
const closeDropDown = useCallback(() => {
console.log({ open });
if (open) setOpen(false);
}, [open]);
const handleValueChange = useCallback(
(selected: Option) => {
function update() {
@@ -148,106 +123,108 @@ function Select<T extends Option>({
}}
selectedItems={selectedItems}
handleValueChange={handleValueChange}>
<div className="relative w-full" ref={ref}>
<div
tabIndex={0}
aria-expanded={open}
onKeyDown={onPressEnterOrSpace}
onClick={toggle}
className={cn(
"flex max-h-[36px] items-center justify-between rounded-md border border-gray-300 text-sm text-gray-400 transition-all duration-300 focus:outline-none",
isDisabled
? " dark:bg-darkgray-200 dark:border-darkgray-300 border-gray-200 bg-gray-100 text-gray-400 dark:text-gray-500"
: "dark:border-darkgray-300 dark:bg-darkgray-50 dark:text-darkgray-500 dark:focus:border-darkgray-700 dark:focus:bg-darkgray-100 dark:focus:text-darkgray-900 dark:hover:text-darkgray-900 bg-white hover:border-gray-600 focus:border-gray-900"
)}>
<div className="flex w-full grow-0 items-center gap-1 overflow-x-hidden">
<>
{((isMultipleValue && selectedItems.length === 0) || selectedItems === null) && (
<div className="py-2.5 px-3 text-gray-400 dark:text-current">
<p>{placeholder}</p>
</div>
)}
{Array.isArray(selectedItems) ? (
<div className="over-flow-x flex gap-1 p-1 ">
{selectedItems.map((item, index) => (
<div
className={cn(
"dark:bg-darkgray-200 flex items-center space-x-2 rounded bg-gray-200 px-2 py-[6px]"
)}
key={index}>
<p
className={cn(
classNames?.tagItemText ??
"dark:text-darkgray-900 cursor-default select-none truncate text-sm leading-none text-gray-700"
)}>
{item.label}
</p>
{!isDisabled && (
<button
onClick={(e) => {
e.stopPropagation();
removeItem(item);
}}>
<FiX
className={
classNames?.tagItemIcon ??
"dark:text-darkgray-700 dark:hover:text-darkgray-900 h-4 w-4 text-gray-500 hover:text-gray-900"
}
/>
</button>
)}
<div className="relative w-full">
<Popover.Root>
<Popover.Trigger>
<div
className={cn(
"min-w-64 flex max-h-[36px] items-center justify-between rounded-md border border-gray-300 text-sm text-gray-400 transition-all duration-300 focus:outline-none",
isDisabled
? " dark:bg-darkgray-200 dark:border-darkgray-300 border-gray-200 bg-gray-100 text-gray-400 dark:text-gray-500"
: "dark:border-darkgray-300 dark:bg-darkgray-50 dark:text-darkgray-500 dark:focus:border-darkgray-700 dark:focus:bg-darkgray-100 dark:focus:text-darkgray-900 dark:hover:text-darkgray-900 bg-white hover:border-gray-600 focus:border-gray-900"
)}>
<div className="flex w-full grow-0 items-center gap-1 overflow-x-hidden">
<>
{((isMultipleValue && selectedItems.length === 0) || selectedItems === null) && (
<div className="py-2.5 px-3 text-gray-400 dark:text-current">
<p>{placeholder}</p>
</div>
))}
</div>
) : (
<div className="dark:text-darkgray-900 py-2.5 px-3 text-sm leading-none text-gray-900">
<p>{selectedItems?.label}</p>
</div>
)}
</>
</div>
)}
<div className="dark:text-darkgray-900 flex flex-none items-center rounded-[6px] p-1.5 text-gray-900 opacity-75 ">
{isClearable && !isDisabled && selectedItems !== null && (
<div className="cursor-pointer" onClick={clearValue}>
<FiX
className={classNames && classNames.closeIcon ? classNames.closeIcon : "h-5 w-5 p-0.5"}
{Array.isArray(selectedItems) ? (
<div className="flex gap-1 overflow-x-scroll p-1 ">
{selectedItems.map((item, index) => (
<div
className={cn(
"dark:bg-darkgray-200 flex items-center space-x-2 rounded bg-gray-200 px-2 py-[6px]"
)}
key={index}>
<p
className={cn(
classNames?.tagItemText ??
"dark:text-darkgray-900 cursor-default select-none truncate text-sm leading-none text-gray-700"
)}>
{item.label}
</p>
{!isDisabled && (
<button
onClick={(e) => {
e.stopPropagation();
removeItem(item);
}}>
<FiX
className={
classNames?.tagItemIcon ??
"dark:text-darkgray-700 dark:hover:text-darkgray-900 h-4 w-4 text-gray-500 hover:text-gray-900"
}
/>
</button>
)}
</div>
))}
</div>
) : (
<div className="dark:text-darkgray-900 py-2.5 px-3 text-sm leading-none text-gray-900">
<p>{selectedItems?.label}</p>
</div>
)}
</>
</div>
<div className="dark:text-darkgray-900 flex flex-none items-center rounded-[6px] p-1.5 text-gray-900 opacity-75 ">
<>
{isClearable && !isDisabled && selectedItems !== null && (
<div className="cursor-pointer" onClick={clearValue}>
<FiX
className={
classNames && classNames.closeIcon ? classNames.closeIcon : "h-5 w-5 p-0.5"
}
/>
</div>
)}
<FiChevronDown className={cn("h-5 w-5 transition duration-300")} />
</>
</div>
</div>
</Popover.Trigger>
<Popover.Portal>
<Popover.Content>
<div
className={
classNames?.menu ??
"dark:bg-darkgray-100 dark:border-darkgray-300 min-w-64 z-10 mt-1.5 overflow-x-hidden rounded border bg-white py-1 text-sm text-gray-700 shadow-sm"
}>
{isSearchable && (
<SearchInput
searchInputRef={searchBoxRef}
value={inputValue}
placeholder={searchInputPlaceholder}
onChange={(e) => setInputValue(e.target.value)}
/>
)}
<Options
searchBoxRef={searchBoxRef}
list={options}
inputValue={inputValue}
isMultiple={isMultiple}
selected={selectedItems}
/>
</div>
)}
<FiChevronDown
className={cn("h-5 w-5 transition duration-300", open && " rotate-180 transform")}
/>
</div>
</div>
{open && !isDisabled && (
<div
tabIndex={-1}
className={
classNames?.menu ??
"dark:bg-darkgray-100 dark:border-darkgray-300 absolute z-10 mt-1.5 w-full max-w-[256px] overflow-x-hidden rounded border bg-white py-1 text-sm text-gray-700 shadow-sm"
}>
{isSearchable && (
<SearchInput
searchInputRef={searchBoxRef}
value={inputValue}
placeholder={searchInputPlaceholder}
onChange={(e) => setInputValue(e.target.value)}
/>
)}
<Options
searchBoxRef={searchBoxRef}
list={options}
inputValue={inputValue}
isMultiple={isMultiple}
selected={selectedItems}
/>
</div>
)}
</Popover.Content>
</Popover.Portal>
</Popover.Root>
</div>
</SelectProvider>
);
@@ -14,7 +14,6 @@ import {
import { Tooltip } from "../tooltip";
import { FiPlus, FiX } from "../icon";
import { Flex } from "./Flex";
<Meta title="Layout/Spacing" />