feat: support selecting multiple library items via shift (#4306)

This commit is contained in:
David Luzar 2021-11-26 12:46:23 +01:00 committed by GitHub
parent b53d1f6f3e
commit 06db702b5d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 117 additions and 67 deletions

View file

@ -6,14 +6,14 @@ import "./CheckboxItem.scss";
export const CheckboxItem: React.FC<{
checked: boolean;
onChange: (checked: boolean) => void;
onChange: (checked: boolean, event: React.MouseEvent) => void;
className?: string;
}> = ({ children, checked, onChange, className }) => {
return (
<div
className={clsx("Checkbox", className, { "is-checked": checked })}
onClick={(event) => {
onChange(!checked);
onChange(!checked, event);
(
(event.currentTarget as HTMLDivElement).querySelector(
".Checkbox-box",

View file

@ -18,6 +18,7 @@ import "./LibraryMenu.scss";
import LibraryMenuItems from "./LibraryMenuItems";
import { EVENT } from "../constants";
import { KEYS } from "../keys";
import { arrayToMap } from "../utils";
const useOnClickOutside = (
ref: RefObject<HTMLElement>,
@ -236,6 +237,10 @@ export const LibraryMenu = ({
],
);
const [lastSelectedItem, setLastSelectedItem] = useState<
LibraryItem["id"] | null
>(null);
return loadingState === "preloading" ? null : (
<Island padding={1} ref={ref} className="layer-ui__library">
{showPublishLibraryDialog && (
@ -271,10 +276,44 @@ export const LibraryMenu = ({
files={files}
id={id}
selectedItems={selectedItems}
onToggle={(id) => {
if (!selectedItems.includes(id)) {
setSelectedItems([...selectedItems, id]);
onToggle={(id, event) => {
const shouldSelect = !selectedItems.includes(id);
if (shouldSelect) {
if (event.shiftKey && lastSelectedItem) {
const rangeStart = libraryItems.findIndex(
(item) => item.id === lastSelectedItem,
);
const rangeEnd = libraryItems.findIndex(
(item) => item.id === id,
);
if (rangeStart === -1 || rangeEnd === -1) {
setSelectedItems([...selectedItems, id]);
return;
}
const selectedItemsMap = arrayToMap(selectedItems);
const nextSelectedIds = libraryItems.reduce(
(acc: LibraryItem["id"][], item, idx) => {
if (
(idx >= rangeStart && idx <= rangeEnd) ||
selectedItemsMap.has(item.id)
) {
acc.push(item.id);
}
return acc;
},
[],
);
setSelectedItems(nextSelectedIds);
} else {
setSelectedItems([...selectedItems, id]);
}
setLastSelectedItem(id);
} else {
setLastSelectedItem(null);
setSelectedItems(selectedItems.filter((_id) => _id !== id));
}
}}

View file

@ -52,7 +52,7 @@ const LibraryMenuItems = ({
library: Library;
id: string;
selectedItems: LibraryItem["id"][];
onToggle: (id: LibraryItem["id"]) => void;
onToggle: (id: LibraryItem["id"], event: React.MouseEvent) => void;
onPublish: () => void;
resetLibrary: () => void;
}) => {
@ -213,10 +213,8 @@ const LibraryMenuItems = ({
onClick={params.onClick || (() => {})}
id={params.item?.id || null}
selected={!!params.item?.id && selectedItems.includes(params.item.id)}
onToggle={() => {
if (params.item?.id) {
onToggle(params.item.id);
}
onToggle={(id, event) => {
onToggle(id, event);
}}
/>
</Stack.Col>

View file

@ -99,8 +99,13 @@
margin-top: -10px;
pointer-events: none;
}
.library-unit--hover .library-unit__adder {
color: $oc-blue-7;
.library-unit:hover .library-unit__adder {
fill: $oc-blue-7;
}
.library-unit:active .library-unit__adder {
animation: none;
transform: scale(0.8);
fill: $oc-black;
}
.library-unit__active {

View file

@ -8,12 +8,15 @@ import { BinaryFiles, LibraryItem } from "../types";
import "./LibraryUnit.scss";
import { CheckboxItem } from "./CheckboxItem";
// fa-plus
const PLUS_ICON = (
<svg viewBox="0 0 1792 1792">
<path
fill="currentColor"
d="M1600 736v192q0 40-28 68t-68 28h-416v416q0 40-28 68t-68 28h-192q-40 0-68-28t-28-68v-416h-416q-40 0-68-28t-28-68v-192q0-40 28-68t68-28h416v-416q0-40 28-68t68-28h192q40 0 68 28t28 68v416h416q40 0 68 28t28 68z"
d="M1600 736v192c0 26.667-9.33 49.333-28 68-18.67 18.67-41.33 28-68 28h-416v416c0 26.67-9.33 49.33-28 68s-41.33 28-68 28H800c-26.667 0-49.333-9.33-68-28s-28-41.33-28-68v-416H288c-26.667 0-49.333-9.33-68-28-18.667-18.667-28-41.333-28-68V736c0-26.667 9.333-49.333 28-68s41.333-28 68-28h416V224c0-26.667 9.333-49.333 28-68s41.333-28 68-28h192c26.67 0 49.33 9.333 68 28s28 41.333 28 68v416h416c26.67 0 49.33 9.333 68 28s28 41.333 28 68Z"
style={{
stroke: "#fff",
strokeWidth: 140,
}}
transform="translate(0 64)"
/>
</svg>
);
@ -33,7 +36,7 @@ export const LibraryUnit = ({
isPending?: boolean;
onClick: () => void;
selected: boolean;
onToggle: (id: string) => void;
onToggle: (id: string, event: React.MouseEvent) => void;
}) => {
const ref = useRef<HTMLDivElement | null>(null);
useEffect(() => {
@ -84,7 +87,17 @@ export const LibraryUnit = ({
})}
ref={ref}
draggable={!!elements}
onClick={!!elements || !!isPending ? onClick : undefined}
onClick={
!!elements || !!isPending
? (event) => {
if (id && event.shiftKey) {
onToggle(id, event);
} else {
onClick();
}
}
: undefined
}
onDragStart={(event) => {
setIsHovered(false);
event.dataTransfer.setData(
@ -97,7 +110,7 @@ export const LibraryUnit = ({
{id && elements && (isHovered || isMobile || selected) && (
<CheckboxItem
checked={selected}
onChange={() => onToggle(id)}
onChange={(checked, event) => onToggle(id, event)}
className="library-unit__checkbox"
/>
)}