implement double click handler on default controls

This commit is contained in:
jeffvli
2025-11-13 20:54:18 -08:00
parent c5e11cca58
commit a75f64d204
6 changed files with 291 additions and 61 deletions
@@ -176,6 +176,7 @@ export const ItemCardControls = ({
icon="ellipsisHorizontal"
onClick={(e) => {
e.stopPropagation();
e.preventDefault();
controls?.onMore?.({
event: e,
internalState,
@@ -183,6 +184,10 @@ export const ItemCardControls = ({
itemType,
});
}}
onDoubleClick={(e) => {
e.stopPropagation();
e.preventDefault();
}}
/>
)}
{controls?.onExpand && (
@@ -260,14 +265,25 @@ interface SecondaryButtonProps {
onClick?: (e: MouseEvent<HTMLButtonElement>) => void;
}
const SecondaryButton = ({ className, icon, onClick }: SecondaryButtonProps) => {
const SecondaryButton = ({
className,
icon,
onClick,
onDoubleClick,
}: SecondaryButtonProps & { onDoubleClick?: (e: MouseEvent<HTMLButtonElement>) => void }) => {
return (
<button
className={clsx(styles.secondaryButton, className)}
onClick={(e) => {
e.stopPropagation();
e.preventDefault();
onClick?.(e);
}}
onDoubleClick={(e) => {
e.stopPropagation();
e.preventDefault();
onDoubleClick?.(e);
}}
>
<Icon icon={icon} size="lg" />
</button>
+124 -36
View File
@@ -15,6 +15,7 @@ import { Image } from '/@/shared/components/image/image';
import { Separator } from '/@/shared/components/separator/separator';
import { Skeleton } from '/@/shared/components/skeleton/skeleton';
import { Text } from '/@/shared/components/text/text';
import { useDoubleClick } from '/@/shared/hooks/use-double-click';
import {
Album,
AlbumArtist,
@@ -138,22 +139,50 @@ const CompactItemCard = ({
}
};
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
const handleClick = useDoubleClick({
onSingleClick: (e: React.MouseEvent<HTMLDivElement>) => {
if (!data || !controls || !internalState) {
return;
}
// Don't trigger selection if clicking on interactive elements
const target = e.target as HTMLElement;
const isInteractiveElement = target.closest(
'button, a, input, select, textarea, [role="button"]',
);
if (isInteractiveElement) {
return;
}
controls.onClick?.({
event: e,
internalState,
item: data as any,
itemType,
});
},
onDoubleClick: (e: React.MouseEvent<HTMLDivElement>) => {
if (!data || !controls || !internalState) {
return;
}
controls.onDoubleClick?.({
event: e,
internalState,
item: data as any,
itemType,
});
},
});
const handleContextMenu = (e: React.MouseEvent<HTMLDivElement>) => {
if (!data || !controls || !internalState) {
return;
}
// Don't trigger selection if clicking on interactive elements
const target = e.target as HTMLElement;
const isInteractiveElement = target.closest(
'button, a, input, select, textarea, [role="button"]',
);
if (isInteractiveElement) {
return;
}
controls.onClick?.({
e.preventDefault();
controls.onMore?.({
event: e,
internalState,
item: data as any,
@@ -170,6 +199,7 @@ const CompactItemCard = ({
<div
className={clsx(styles.imageContainer, { [styles.isRound]: isRound })}
onClick={handleClick}
onContextMenu={handleContextMenu}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
@@ -242,22 +272,50 @@ const DefaultItemCard = ({
}
};
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
const handleClick = useDoubleClick({
onSingleClick: (e: React.MouseEvent<HTMLDivElement>) => {
if (!data || !controls || !internalState) {
return;
}
// Don't trigger selection if clicking on interactive elements
const target = e.target as HTMLElement;
const isInteractiveElement = target.closest(
'button, a, input, select, textarea, [role="button"]',
);
if (isInteractiveElement) {
return;
}
controls.onClick?.({
event: e,
internalState,
item: data as any,
itemType,
});
},
onDoubleClick: (e: React.MouseEvent<HTMLDivElement>) => {
if (!data || !controls || !internalState) {
return;
}
controls.onDoubleClick?.({
event: e,
internalState,
item: data as any,
itemType,
});
},
});
const handleContextMenu = (e: React.MouseEvent<HTMLDivElement>) => {
if (!data || !controls || !internalState) {
return;
}
// Don't trigger selection if clicking on interactive elements
const target = e.target as HTMLElement;
const isInteractiveElement = target.closest(
'button, a, input, select, textarea, [role="button"]',
);
if (isInteractiveElement) {
return;
}
controls.onClick?.({
e.preventDefault();
controls.onMore?.({
event: e,
internalState,
item: data as any,
@@ -274,6 +332,7 @@ const DefaultItemCard = ({
<div
className={clsx(styles.imageContainer, { [styles.isRound]: isRound })}
onClick={handleClick}
onContextMenu={handleContextMenu}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
@@ -390,22 +449,50 @@ const PosterItemCard = ({
}
};
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
const handleClick = useDoubleClick({
onSingleClick: (e: React.MouseEvent<HTMLDivElement>) => {
if (!data || !controls || !internalState) {
return;
}
// Don't trigger selection if clicking on interactive elements
const target = e.target as HTMLElement;
const isInteractiveElement = target.closest(
'button, a, input, select, textarea, [role="button"]',
);
if (isInteractiveElement) {
return;
}
controls.onClick?.({
event: e,
internalState,
item: data as any,
itemType,
});
},
onDoubleClick: (e: React.MouseEvent<HTMLDivElement>) => {
if (!data || !controls || !internalState) {
return;
}
controls.onDoubleClick?.({
event: e,
internalState,
item: data as any,
itemType,
});
},
});
const handleContextMenu = (e: React.MouseEvent<HTMLDivElement>) => {
if (!data || !controls || !internalState) {
return;
}
// Don't trigger selection if clicking on interactive elements
const target = e.target as HTMLElement;
const isInteractiveElement = target.closest(
'button, a, input, select, textarea, [role="button"]',
);
if (isInteractiveElement) {
return;
}
controls.onClick?.({
e.preventDefault();
controls.onMore?.({
event: e,
internalState,
item: data as any,
@@ -424,6 +511,7 @@ const PosterItemCard = ({
<div
className={clsx(styles.imageContainer, { [styles.isRound]: isRound })}
onClick={handleClick}
onContextMenu={handleContextMenu}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>