feat: Keyboard navigation spreadsheet layout for issues (#3564)
* enable keyboard navigation for spreadsheet layout * move the logic to table level instead of cell level * fix perf issue that made it unusable * fix scroll issue with navigation * fix build errors
This commit is contained in:
parent
a43dfc097d
commit
fb3dd77b66
31 changed files with 368 additions and 126 deletions
|
|
@ -23,6 +23,7 @@ type Props = TDropdownProps & {
|
|||
dropdownArrow?: boolean;
|
||||
dropdownArrowClassName?: string;
|
||||
onChange: (val: string | null) => void;
|
||||
onClose?: () => void;
|
||||
projectId: string;
|
||||
value: string | null;
|
||||
};
|
||||
|
|
@ -47,6 +48,7 @@ export const CycleDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrowClassName = "",
|
||||
hideIcon = false,
|
||||
onChange,
|
||||
onClose,
|
||||
placeholder = "Cycle",
|
||||
placement,
|
||||
projectId,
|
||||
|
|
@ -123,8 +125,10 @@ export const CycleDropdown: React.FC<Props> = observer((props) => {
|
|||
};
|
||||
|
||||
const handleClose = () => {
|
||||
if (isOpen) setIsOpen(false);
|
||||
if (!isOpen) return;
|
||||
setIsOpen(false);
|
||||
if (referenceElement) referenceElement.blur();
|
||||
onClose && onClose();
|
||||
};
|
||||
|
||||
const toggleDropdown = () => {
|
||||
|
|
@ -163,7 +167,7 @@ export const CycleDropdown: React.FC<Props> = observer((props) => {
|
|||
<button
|
||||
ref={setReferenceElement}
|
||||
type="button"
|
||||
className={cn("block h-full w-full outline-none", buttonContainerClassName)}
|
||||
className={cn("clickable block h-full w-full outline-none", buttonContainerClassName)}
|
||||
onClick={handleOnClick}
|
||||
>
|
||||
{button}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ type Props = TDropdownProps & {
|
|||
minDate?: Date;
|
||||
maxDate?: Date;
|
||||
onChange: (val: Date | null) => void;
|
||||
onClose?: () => void;
|
||||
value: Date | string | null;
|
||||
closeOnSelect?: boolean;
|
||||
};
|
||||
|
|
@ -42,6 +43,7 @@ export const DateDropdown: React.FC<Props> = (props) => {
|
|||
minDate,
|
||||
maxDate,
|
||||
onChange,
|
||||
onClose,
|
||||
placeholder = "Date",
|
||||
placement,
|
||||
showTooltip = false,
|
||||
|
|
@ -74,8 +76,10 @@ export const DateDropdown: React.FC<Props> = (props) => {
|
|||
};
|
||||
|
||||
const handleClose = () => {
|
||||
if (isOpen) setIsOpen(false);
|
||||
if (!isOpen) return;
|
||||
setIsOpen(false);
|
||||
if (referenceElement) referenceElement.blur();
|
||||
onClose && onClose();
|
||||
};
|
||||
|
||||
const toggleDropdown = () => {
|
||||
|
|
@ -112,7 +116,7 @@ export const DateDropdown: React.FC<Props> = (props) => {
|
|||
ref={setReferenceElement}
|
||||
type="button"
|
||||
className={cn(
|
||||
"block h-full max-w-full outline-none",
|
||||
"clickable block h-full max-w-full outline-none",
|
||||
{
|
||||
"cursor-not-allowed text-custom-text-200": disabled,
|
||||
"cursor-pointer": !disabled,
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ type Props = TDropdownProps & {
|
|||
dropdownArrow?: boolean;
|
||||
dropdownArrowClassName?: string;
|
||||
onChange: (val: number | null) => void;
|
||||
onClose?: () => void;
|
||||
projectId: string;
|
||||
value: number | null;
|
||||
};
|
||||
|
|
@ -46,6 +47,7 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrowClassName = "",
|
||||
hideIcon = false,
|
||||
onChange,
|
||||
onClose,
|
||||
placeholder = "Estimate",
|
||||
placement,
|
||||
projectId,
|
||||
|
|
@ -112,8 +114,10 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
|
|||
};
|
||||
|
||||
const handleClose = () => {
|
||||
if (isOpen) setIsOpen(false);
|
||||
if (!isOpen) return;
|
||||
setIsOpen(false);
|
||||
if (referenceElement) referenceElement.blur();
|
||||
onClose && onClose();
|
||||
};
|
||||
|
||||
const toggleDropdown = () => {
|
||||
|
|
@ -152,7 +156,7 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
|
|||
<button
|
||||
ref={setReferenceElement}
|
||||
type="button"
|
||||
className={cn("block h-full w-full outline-none", buttonContainerClassName)}
|
||||
className={cn("clickable block h-full w-full outline-none", buttonContainerClassName)}
|
||||
onClick={handleOnClick}
|
||||
>
|
||||
{button}
|
||||
|
|
@ -162,7 +166,7 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
|
|||
ref={setReferenceElement}
|
||||
type="button"
|
||||
className={cn(
|
||||
"block h-full max-w-full outline-none",
|
||||
"clickable block h-full max-w-full outline-none",
|
||||
{
|
||||
"cursor-not-allowed text-custom-text-200": disabled,
|
||||
"cursor-pointer": !disabled,
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import { BUTTON_VARIANTS_WITH_TEXT } from "../constants";
|
|||
|
||||
type Props = {
|
||||
projectId: string;
|
||||
onClose?: () => void;
|
||||
} & MemberDropdownProps;
|
||||
|
||||
export const ProjectMemberDropdown: React.FC<Props> = observer((props) => {
|
||||
|
|
@ -36,6 +37,7 @@ export const ProjectMemberDropdown: React.FC<Props> = observer((props) => {
|
|||
hideIcon = false,
|
||||
multiple,
|
||||
onChange,
|
||||
onClose,
|
||||
placeholder = "Members",
|
||||
placement,
|
||||
projectId,
|
||||
|
|
@ -105,8 +107,10 @@ export const ProjectMemberDropdown: React.FC<Props> = observer((props) => {
|
|||
};
|
||||
|
||||
const handleClose = () => {
|
||||
if (isOpen) setIsOpen(false);
|
||||
if (!isOpen) return;
|
||||
setIsOpen(false);
|
||||
if (referenceElement) referenceElement.blur();
|
||||
onClose && onClose();
|
||||
};
|
||||
|
||||
const toggleDropdown = () => {
|
||||
|
|
@ -144,7 +148,7 @@ export const ProjectMemberDropdown: React.FC<Props> = observer((props) => {
|
|||
<button
|
||||
ref={setReferenceElement}
|
||||
type="button"
|
||||
className={cn("block h-full w-full outline-none", buttonContainerClassName)}
|
||||
className={cn("clickable block h-full w-full outline-none", buttonContainerClassName)}
|
||||
onClick={handleOnClick}
|
||||
>
|
||||
{button}
|
||||
|
|
@ -154,7 +158,7 @@ export const ProjectMemberDropdown: React.FC<Props> = observer((props) => {
|
|||
ref={setReferenceElement}
|
||||
type="button"
|
||||
className={cn(
|
||||
"block h-full max-w-full outline-none",
|
||||
"clickable block h-full max-w-full outline-none",
|
||||
{
|
||||
"cursor-not-allowed text-custom-text-200": disabled,
|
||||
"cursor-pointer": !disabled,
|
||||
|
|
|
|||
1
web/components/dropdowns/member/types.d.ts
vendored
1
web/components/dropdowns/member/types.d.ts
vendored
|
|
@ -5,6 +5,7 @@ export type MemberDropdownProps = TDropdownProps & {
|
|||
dropdownArrow?: boolean;
|
||||
dropdownArrowClassName?: string;
|
||||
placeholder?: string;
|
||||
onClose?: () => void;
|
||||
} & (
|
||||
| {
|
||||
multiple: false;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ export const WorkspaceMemberDropdown: React.FC<MemberDropdownProps> = observer((
|
|||
hideIcon = false,
|
||||
multiple,
|
||||
onChange,
|
||||
onClose,
|
||||
placeholder = "Members",
|
||||
placement,
|
||||
showTooltip = false,
|
||||
|
|
@ -95,8 +96,10 @@ export const WorkspaceMemberDropdown: React.FC<MemberDropdownProps> = observer((
|
|||
};
|
||||
|
||||
const handleClose = () => {
|
||||
if (isOpen) setIsOpen(false);
|
||||
if (!isOpen) return;
|
||||
setIsOpen(false);
|
||||
if (referenceElement) referenceElement.blur();
|
||||
onClose && onClose();
|
||||
};
|
||||
|
||||
const toggleDropdown = () => {
|
||||
|
|
@ -134,7 +137,7 @@ export const WorkspaceMemberDropdown: React.FC<MemberDropdownProps> = observer((
|
|||
<button
|
||||
ref={setReferenceElement}
|
||||
type="button"
|
||||
className={cn("block h-full w-full outline-none", buttonContainerClassName)}
|
||||
className={cn("clickable block h-full w-full outline-none", buttonContainerClassName)}
|
||||
onClick={handleOnClick}
|
||||
>
|
||||
{button}
|
||||
|
|
@ -144,7 +147,7 @@ export const WorkspaceMemberDropdown: React.FC<MemberDropdownProps> = observer((
|
|||
ref={setReferenceElement}
|
||||
type="button"
|
||||
className={cn(
|
||||
"block h-full max-w-full outline-none",
|
||||
"clickable block h-full max-w-full outline-none",
|
||||
{
|
||||
"cursor-not-allowed text-custom-text-200": disabled,
|
||||
"cursor-pointer": !disabled,
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ type Props = TDropdownProps & {
|
|||
dropdownArrowClassName?: string;
|
||||
projectId: string;
|
||||
showCount?: boolean;
|
||||
onClose?: () => void;
|
||||
} & (
|
||||
| {
|
||||
multiple: false;
|
||||
|
|
@ -151,6 +152,7 @@ export const ModuleDropdown: React.FC<Props> = observer((props) => {
|
|||
hideIcon = false,
|
||||
multiple,
|
||||
onChange,
|
||||
onClose,
|
||||
placeholder = "Module",
|
||||
placement,
|
||||
projectId,
|
||||
|
|
@ -226,8 +228,10 @@ export const ModuleDropdown: React.FC<Props> = observer((props) => {
|
|||
};
|
||||
|
||||
const handleClose = () => {
|
||||
if (isOpen) setIsOpen(false);
|
||||
if (!isOpen) return;
|
||||
setIsOpen(false);
|
||||
if (referenceElement) referenceElement.blur();
|
||||
onClose && onClose();
|
||||
};
|
||||
|
||||
const toggleDropdown = () => {
|
||||
|
|
@ -271,7 +275,7 @@ export const ModuleDropdown: React.FC<Props> = observer((props) => {
|
|||
<button
|
||||
ref={setReferenceElement}
|
||||
type="button"
|
||||
className={cn("block h-full w-full outline-none", buttonContainerClassName)}
|
||||
className={cn("clickable block h-full w-full outline-none", buttonContainerClassName)}
|
||||
onClick={handleOnClick}
|
||||
>
|
||||
{button}
|
||||
|
|
@ -281,7 +285,7 @@ export const ModuleDropdown: React.FC<Props> = observer((props) => {
|
|||
ref={setReferenceElement}
|
||||
type="button"
|
||||
className={cn(
|
||||
"block h-full max-w-full outline-none",
|
||||
"clickable block h-full max-w-full outline-none",
|
||||
{
|
||||
"cursor-not-allowed text-custom-text-200": disabled,
|
||||
"cursor-pointer": !disabled,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ type Props = TDropdownProps & {
|
|||
dropdownArrowClassName?: string;
|
||||
highlightUrgent?: boolean;
|
||||
onChange: (val: TIssuePriorities) => void;
|
||||
onClose?: () => void;
|
||||
value: TIssuePriorities;
|
||||
};
|
||||
|
||||
|
|
@ -260,6 +261,7 @@ export const PriorityDropdown: React.FC<Props> = (props) => {
|
|||
hideIcon = false,
|
||||
highlightUrgent = true,
|
||||
onChange,
|
||||
onClose,
|
||||
placement,
|
||||
showTooltip = false,
|
||||
tabIndex,
|
||||
|
|
@ -308,8 +310,10 @@ export const PriorityDropdown: React.FC<Props> = (props) => {
|
|||
};
|
||||
|
||||
const handleClose = () => {
|
||||
if (isOpen) setIsOpen(false);
|
||||
if (!isOpen) return;
|
||||
setIsOpen(false);
|
||||
if (referenceElement) referenceElement.blur();
|
||||
onClose && onClose();
|
||||
};
|
||||
|
||||
const toggleDropdown = () => {
|
||||
|
|
@ -360,7 +364,7 @@ export const PriorityDropdown: React.FC<Props> = (props) => {
|
|||
<button
|
||||
ref={setReferenceElement}
|
||||
type="button"
|
||||
className={cn("block h-full w-full outline-none", buttonContainerClassName)}
|
||||
className={cn("clickable block h-full w-full outline-none", buttonContainerClassName)}
|
||||
onClick={handleOnClick}
|
||||
>
|
||||
{button}
|
||||
|
|
@ -370,7 +374,7 @@ export const PriorityDropdown: React.FC<Props> = (props) => {
|
|||
ref={setReferenceElement}
|
||||
type="button"
|
||||
className={cn(
|
||||
"block h-full max-w-full outline-none",
|
||||
"clickable block h-full max-w-full outline-none",
|
||||
{
|
||||
"cursor-not-allowed text-custom-text-200": disabled,
|
||||
"cursor-pointer": !disabled,
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ type Props = TDropdownProps & {
|
|||
dropdownArrow?: boolean;
|
||||
dropdownArrowClassName?: string;
|
||||
onChange: (val: string) => void;
|
||||
onClose?: () => void;
|
||||
value: string | null;
|
||||
};
|
||||
|
||||
|
|
@ -37,6 +38,7 @@ export const ProjectDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrowClassName = "",
|
||||
hideIcon = false,
|
||||
onChange,
|
||||
onClose,
|
||||
placeholder = "Project",
|
||||
placement,
|
||||
showTooltip = false,
|
||||
|
|
@ -97,7 +99,9 @@ export const ProjectDropdown: React.FC<Props> = observer((props) => {
|
|||
};
|
||||
|
||||
const handleClose = () => {
|
||||
if (isOpen) setIsOpen(false);
|
||||
if (!isOpen) return;
|
||||
setIsOpen(false);
|
||||
onClose && onClose();
|
||||
if (referenceElement) referenceElement.blur();
|
||||
};
|
||||
|
||||
|
|
@ -137,7 +141,7 @@ export const ProjectDropdown: React.FC<Props> = observer((props) => {
|
|||
<button
|
||||
ref={setReferenceElement}
|
||||
type="button"
|
||||
className={cn("block h-full w-full outline-none", buttonContainerClassName)}
|
||||
className={cn("clickable block h-full w-full outline-none", buttonContainerClassName)}
|
||||
onClick={handleOnClick}
|
||||
>
|
||||
{button}
|
||||
|
|
@ -147,7 +151,7 @@ export const ProjectDropdown: React.FC<Props> = observer((props) => {
|
|||
ref={setReferenceElement}
|
||||
type="button"
|
||||
className={cn(
|
||||
"block h-full max-w-full outline-none",
|
||||
"clickable block h-full max-w-full outline-none",
|
||||
{
|
||||
"cursor-not-allowed text-custom-text-200": disabled,
|
||||
"cursor-pointer": !disabled,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ type Props = TDropdownProps & {
|
|||
dropdownArrow?: boolean;
|
||||
dropdownArrowClassName?: string;
|
||||
onChange: (val: string) => void;
|
||||
onClose?: () => void;
|
||||
projectId: string;
|
||||
value: string;
|
||||
};
|
||||
|
|
@ -39,6 +40,7 @@ export const StateDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrowClassName = "",
|
||||
hideIcon = false,
|
||||
onChange,
|
||||
onClose,
|
||||
placement,
|
||||
projectId,
|
||||
showTooltip = false,
|
||||
|
|
@ -94,7 +96,9 @@ export const StateDropdown: React.FC<Props> = observer((props) => {
|
|||
};
|
||||
|
||||
const handleClose = () => {
|
||||
if (isOpen) setIsOpen(false);
|
||||
if (!isOpen) return;
|
||||
setIsOpen(false);
|
||||
onClose && onClose();
|
||||
if (referenceElement) referenceElement.blur();
|
||||
};
|
||||
|
||||
|
|
@ -134,7 +138,7 @@ export const StateDropdown: React.FC<Props> = observer((props) => {
|
|||
<button
|
||||
ref={setReferenceElement}
|
||||
type="button"
|
||||
className={cn("block h-full w-full outline-none", buttonContainerClassName)}
|
||||
className={cn("clickable block h-full w-full outline-none", buttonContainerClassName)}
|
||||
onClick={handleOnClick}
|
||||
>
|
||||
{button}
|
||||
|
|
@ -144,7 +148,7 @@ export const StateDropdown: React.FC<Props> = observer((props) => {
|
|||
ref={setReferenceElement}
|
||||
type="button"
|
||||
className={cn(
|
||||
"block h-full max-w-full outline-none",
|
||||
"clickable block h-full max-w-full outline-none",
|
||||
{
|
||||
"cursor-not-allowed text-custom-text-200": disabled,
|
||||
"cursor-pointer": !disabled,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue