implement list multiselection

This commit is contained in:
jeffvli
2025-11-08 15:35:10 -08:00
parent 7a4326f98d
commit a87d5ef8d8
6 changed files with 217 additions and 20 deletions
@@ -1,13 +1,26 @@
.container {
position: relative;
display: flex;
flex-direction: column;
width: 100%;
padding: var(--theme-spacing-md);
overflow: hidden;
user-select: none;
background-color: var(--theme-colors-surface);
border-radius: var(--theme-radius-md);
}
.container.previewed {
outline: 2px dashed var(--theme-colors-primary);
outline-offset: 2px;
opacity: 0.7;
}
.container.selected {
outline: 2px solid var(--theme-colors-primary);
outline-offset: 2px;
}
.image-container {
position: relative;
width: 100%;
@@ -105,12 +105,17 @@ const CompactItemCard = ({
controls,
data,
imageUrl,
internalState,
isRound,
itemType,
rows,
withControls,
}: ItemCardDerivativeProps) => {
const [showControls, setShowControls] = useState(false);
const isSelected =
data && internalState && typeof data === 'object' && 'id' in data
? internalState.isSelected((data as any).id)
: false;
if (data) {
const handleMouseEnter = () => {
@@ -126,11 +131,34 @@ const CompactItemCard = ({
};
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
// controls?.onClick?.(data, itemType, e);
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,
});
};
return (
<div className={clsx(styles.container, styles.compact)}>
<div
className={clsx(styles.container, styles.compact, {
[styles.selected]: isSelected,
})}
>
<div
className={clsx(styles.imageContainer, { [styles.isRound]: isRound })}
onClick={handleClick}
@@ -181,12 +209,17 @@ const DefaultItemCard = ({
controls,
data,
imageUrl,
internalState,
isRound,
itemType,
rows,
withControls,
}: ItemCardDerivativeProps) => {
const [showControls, setShowControls] = useState(false);
const isSelected =
data && internalState && typeof data === 'object' && 'id' in data
? internalState.isSelected((data as any).id)
: false;
if (data) {
const handleMouseEnter = () => {
@@ -202,11 +235,34 @@ const DefaultItemCard = ({
};
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
// controls?.onClick?.(data, itemType, e);
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,
});
};
return (
<div className={clsx(styles.container)}>
<div
className={clsx(styles.container, {
[styles.selected]: isSelected,
})}
>
<div
className={clsx(styles.imageContainer, { [styles.isRound]: isRound })}
onClick={handleClick}
@@ -264,6 +320,10 @@ const PosterItemCard = ({
withControls,
}: ItemCardDerivativeProps) => {
const [showControls, setShowControls] = useState(false);
const isSelected =
data && internalState && typeof data === 'object' && 'id' in data
? internalState.isSelected((data as any).id)
: false;
if (data) {
const handleMouseEnter = () => {
@@ -279,11 +339,34 @@ const PosterItemCard = ({
};
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
// controls?.onClick?.(data, itemType, e);
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,
});
};
return (
<div className={clsx(styles.container, styles.poster)}>
<div
className={clsx(styles.container, styles.poster, {
[styles.selected]: isSelected,
})}
>
<div
className={clsx(styles.imageContainer, { [styles.isRound]: isRound })}
onClick={handleClick}