feat: Add useActiveDoubleClick hook for improved double-click handling (#39474)

This commit is contained in:
Hetu Nandu 2025-02-28 10:33:26 +05:30 committed by GitHub
parent 635aa0621b
commit efa90ea1d6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 61 additions and 19 deletions

View File

@ -6,6 +6,7 @@ import { DismissibleTab } from "../../DismissibleTab";
import { EditableEntityName } from "../EditableEntityName";
import type { EditableDismissibleTabProps } from "./EditableDismissibleTab.types";
import { useActiveDoubleClick } from "../../__hooks__";
export const EditableDismissibleTab = (props: EditableDismissibleTabProps) => {
const {
@ -33,7 +34,13 @@ export const EditableDismissibleTab = (props: EditableDismissibleTabProps) => {
const isEditing = propIsEditing ?? localIsEditing;
const handleEnterEditMode = propOnEnterEditMode ?? localOnEnterEditMode;
const handleExitEditMode = propOnExitEditMode ?? localOnExitEditMode;
const handleDoubleClick = isEditable ? handleEnterEditMode : noop;
const doubleClickOverride = useActiveDoubleClick(
isActive,
handleEnterEditMode,
);
const handleDoubleClick = isEditable ? doubleClickOverride : noop;
return (
<DismissibleTab

View File

@ -3,8 +3,16 @@ import { ListItem } from "../../../List";
import type { EntityItemProps } from "./EntityItem.types";
import clx from "classnames";
import { EditableEntityName } from "../../EditableEntityName";
import { useActiveDoubleClick } from "../../../__hooks__";
export const EntityItem = (props: EntityItemProps) => {
const { onDoubleClick, startIcon, ...rest } = props;
const doubleClickOverride = useActiveDoubleClick(
props.isSelected || false,
onDoubleClick,
);
const {
canEdit,
isEditing,
@ -14,8 +22,6 @@ export const EntityItem = (props: EntityItemProps) => {
validateName,
} = props.nameEditorConfig;
const { startIcon, ...rest } = props;
const inEditMode = canEdit ? isEditing : false;
// Use List Item custom title prop to show the editable name
@ -61,6 +67,7 @@ export const EntityItem = (props: EntityItemProps) => {
customTitleComponent={customTitle}
data-testid={`t--entity-item-${props.title}`}
id={"entity-" + props.id}
onDoubleClick={doubleClickOverride}
rightControl={rightControl}
/>
);

View File

@ -1,2 +1,3 @@
export { useDOMRef } from "./useDomRef";
export { useEditableText } from "./useEditableText";
export { useActiveDoubleClick } from "./useActiveDoubleClick";

View File

@ -0,0 +1,43 @@
import { noop } from "lodash";
import { useEffect, useMemo } from "react";
import { useBoolean } from "usehooks-ts";
export function useActiveDoubleClick(
isActive: boolean,
onDoubleClick?: () => void,
) {
const {
setFalse: setCannotDoubleClick,
setTrue: setCanDoubleClick,
value: canDoubleClick,
} = useBoolean();
useEffect(
function handleDoubleClickEnableBasedOnSelection() {
let timeoutId: ReturnType<typeof setTimeout>;
if (isActive) {
timeoutId = setTimeout(() => {
setCanDoubleClick();
}, 200);
} else {
setCannotDoubleClick();
}
return () => {
clearTimeout(timeoutId);
};
},
[isActive, setCanDoubleClick, setCannotDoubleClick],
);
const handleDoubleClick = useMemo(() => {
if (!canDoubleClick || !onDoubleClick) {
return noop;
}
return onDoubleClick;
}, [canDoubleClick, onDoubleClick]);
return handleDoubleClick;
}

View File

@ -115,22 +115,6 @@ export function useEditableText(
[name, previousName, isEditing],
);
// TODO: This is a temporary fix to focus the input after context retention applies focus to its target
// this is a nasty hack to re-focus the input after context retention applies focus to its target
// this will be addressed in a future task, likely by a focus retention modification
useEffect(
function recaptureFocusInEventOfFocusRetention() {
const input = inputRef.current;
if (isEditing && input) {
setTimeout(() => {
input.focus();
}, 200);
}
},
[isEditing, inputRef],
);
return [
inputRef,
editableName,