Skip to content

Commit

Permalink
Adding multi selects on mobile view with long press (#1470)
Browse files Browse the repository at this point in the history
* using long press

* dragg preview problems

* typos

* events almost ready

* resets

* long press options

* long press updates

* formats

* dark mode colors

* added hover with breakpoints

* lingui extract

* Apply suggestions from code review

Co-authored-by: Thibaut Sardan <33178835+Tbaut@users.noreply.github.com>

* curly spacing

* borders

* clicks proper placement

* reverted linting

* removed preview on mobile

Co-authored-by: Thibaut Sardan <33178835+Tbaut@users.noreply.github.com>
Co-authored-by: GitHub Actions <actions@github.com>
Co-authored-by: Michael Yankelev <12774278+FSM1@users.noreply.github.com>
  • Loading branch information
4 people authored Sep 3, 2021
1 parent 161d0cd commit 8625789
Show file tree
Hide file tree
Showing 11 changed files with 158 additions and 70 deletions.
24 changes: 13 additions & 11 deletions packages/common-components/src/Table/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ITheme, makeStyles, createStyles } from "@chainsafe/common-theme"
import clsx from "clsx"

const useStyles = makeStyles(
({ animation, constants, palette, overrides }: ITheme) =>
({ animation, constants, palette, overrides, breakpoints }: ITheme) =>
createStyles({
root: {
display: "flex",
Expand All @@ -28,17 +28,19 @@ const useStyles = makeStyles(
...overrides?.Table?.table?.dense
},
hover: {
"& tr:hover": {
backgroundColor: palette.additional["gray"][2]
},
"& tr:nth-child(even)": {
"&:hover": {
[breakpoints.up("md")]: {
"& tr:hover": {
backgroundColor: palette.additional["gray"][2]
}
},
"&.selected": {
"&:hover": {
backgroundColor: palette.additional["gray"][4]
},
"& tr:nth-child(even)": {
"&:hover": {
backgroundColor: palette.additional["gray"][2]
}
},
"&.selected": {
"&:hover": {
backgroundColor: palette.additional["gray"][4]
}
}
},
...overrides?.Table?.table?.hover
Expand Down
3 changes: 2 additions & 1 deletion packages/common-theme/src/Hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useOnClickOutside } from "./useOnClickOutside"
import { useMediaQuery } from "./useMediaQuery"
import { useDoubleClick } from "./useDoubleClick"
import { useLongPress, LongPressEvents } from "./useLongPress"

export { useOnClickOutside, useMediaQuery, useDoubleClick }
export { useOnClickOutside, useMediaQuery, useDoubleClick, useLongPress, LongPressEvents }
66 changes: 66 additions & 0 deletions packages/common-theme/src/Hooks/useLongPress.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { useCallback, useRef, useState } from "react"

export interface LongPressEvents {
onMouseDown: (e: React.MouseEvent) => void
onTouchStart: (e: React.TouchEvent) => void
onMouseUp: (e: React.MouseEvent) => void
onMouseLeave: (e: React.MouseEvent) => void
onTouchEnd: (e: React.TouchEvent) => void
}

export const useLongPress = (
onLongPress: ((e?: React.MouseEvent) => void) | null,
onClick: ((e?: React.MouseEvent) => void) | null,
delay = 300
): LongPressEvents => {
const [longPressTriggered, setLongPressTriggered] = useState(false)
const timeout: any = useRef()
const target: any = useRef()

const start = useCallback(
(event: any) => {
if (event.target) {
event.target.addEventListener("touchend", preventDefault, {
passive: false
})
target.current = event.target
}
timeout.current = setTimeout(() => {
onLongPress && onLongPress(event)
setLongPressTriggered(true)
}, delay)

}, [onLongPress, delay]
)

const clear = useCallback(
(shouldTriggerClick = true) => {
timeout.current && clearTimeout(timeout.current)
shouldTriggerClick && !longPressTriggered && onClick && onClick()
setLongPressTriggered(false)
if (target.current) {
target.current.removeEventListener("touchend", preventDefault)
}
}, [onClick, longPressTriggered]
)

return {
onMouseDown: (e: React.MouseEvent) => start(e),
onTouchStart: (e: React.TouchEvent) => start(e),
onMouseUp: (e: React.MouseEvent) => clear(e),
onMouseLeave: () => clear(false),
onTouchEnd: (e: React.TouchEvent) => clear(e)
}
}

const isTouchEvent = (event: any) => {
return "touches" in event
}

const preventDefault = (event: any) => {
if (!isTouchEvent(event)) return

if (event.touches.length < 2 && event.preventDefault) {
event.preventDefault()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,18 +68,14 @@ const BinFileBrowser: React.FC<IFileBrowserModuleProps> = ({ controls = false }:

refreshContents()
refreshBuckets()
const message = `${
itemToDelete.isFolder ? t`Folder` : t`File`
} ${t`deleted successfully`}`
const message = `${itemToDelete.isFolder ? t`Folder` : t`File`} ${t`deleted successfully`}`
addToastMessage({
message: message,
appearance: "success"
})
return Promise.resolve()
} catch (error) {
const message = `${t`There was an error deleting this`} ${
itemToDelete.isFolder ? t`folder` : t`file`
}`
const message = `${t`There was an error deleting this`} ${itemToDelete.isFolder ? t`folder` : t`file`}`
addToastMessage({
message: message,
appearance: "error"
Expand All @@ -105,24 +101,21 @@ const BinFileBrowser: React.FC<IFileBrowserModuleProps> = ({ controls = false }:
try {
await filesApiClient.moveBucketObjects(
bucket.id,
{ path: getPathWithFile(currentPath, itemToRestore.name),
{
path: getPathWithFile(currentPath, itemToRestore.name),
new_path: getPathWithFile(newPath, itemToRestore.name),
destination: buckets.find(b => b.type === "csf")?.id
}
)

const message = `${
itemToRestore.isFolder ? t`Folder` : t`File`
} ${t`recovered successfully`}`
const message = `${itemToRestore.isFolder ? t`Folder` : t`File`} ${t`recovered successfully`}`

addToastMessage({
message: message,
appearance: "success"
})
} catch (error) {
const message = `${t`There was an error recovering this`} ${
itemToRestore.isFolder ? t`folder` : t`file`
}`
const message = `${t`There was an error recovering this`} ${itemToRestore.isFolder ? t`folder` : t`file`}`
addToastMessage({
message: message,
appearance: "error"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useCallback, useEffect, useRef } from "react"
import { makeStyles, createStyles, useThemeSwitcher, useOnClickOutside } from "@chainsafe/common-theme"
import { makeStyles, createStyles, useThemeSwitcher, useOnClickOutside, LongPressEvents } from "@chainsafe/common-theme"
import { t } from "@lingui/macro"
import clsx from "clsx"
import {
Expand Down Expand Up @@ -49,7 +49,7 @@ const useStyles = makeStyles(({ breakpoints, constants, palette }: CSFTheme) =>
height: constants.generalUnit * 16
},
"&.highlighted": {
border: `1px solid ${palette.primary.main}`
border: `1px solid ${constants.fileSystemItemRow.borderColor}`
}
},
renameInput: {
Expand Down Expand Up @@ -106,7 +106,7 @@ const useStyles = makeStyles(({ breakpoints, constants, palette }: CSFTheme) =>
padding: 0
}
},
focusVisible:{
focusVisible: {
backgroundColor: "transparent !important"
}
})
Expand All @@ -122,11 +122,12 @@ interface IFileSystemTableItemProps {
onFolderOrFileClicks: (e?: React.MouseEvent) => void
icon: React.ReactNode
preview: ConnectDragPreview
setEditing: (editing: string | undefined) => void
setEditing: (editing: string | undefined) => void
handleRename?: (path: string, newPath: string) => Promise<void>
currentPath: string | undefined
menuItems: IMenuItem[]
resetSelectedFiles: () => void
longPressEvents?: LongPressEvents
}

const FileSystemGridItem = React.forwardRef(
Expand All @@ -143,7 +144,8 @@ const FileSystemGridItem = React.forwardRef(
handleRename,
menuItems,
resetSelectedFiles,
preview
preview,
longPressEvents
}: IFileSystemTableItemProps, forwardedRef: any) => {
const classes = useStyles()
const { name, cid } = file
Expand All @@ -155,7 +157,7 @@ const FileSystemGridItem = React.forwardRef(
name
},
validationSchema: nameValidator,
onSubmit: (values: {name: string}) => {
onSubmit: (values: { name: string }) => {
const newName = values.name.trim()

newName && handleRename && handleRename(file.cid, newName)
Expand Down Expand Up @@ -192,7 +194,7 @@ const FileSystemGridItem = React.forwardRef(

useOnClickOutside(formRef, stopEditing)

return (
return (
<div
className={classes.gridViewContainer}
ref={forwardedRef}
Expand All @@ -205,6 +207,7 @@ const FileSystemGridItem = React.forwardRef(
className={clsx(classes.gridViewIconNameBox)}
ref={preview}
onClick={(e) => onFolderOrFileClicks(e)}
{...longPressEvents}
>
<div
className={clsx(
Expand Down Expand Up @@ -232,7 +235,7 @@ const FileSystemGridItem = React.forwardRef(
stopEditing()
}
}}
placeholder = {isFolder
placeholder={isFolder
? t`Please enter a folder name`
: t`Please enter a file name`
}
Expand All @@ -247,7 +250,7 @@ const FileSystemGridItem = React.forwardRef(
<div>
<Menu
testId='fileDropdown'
icon={<MoreIcon className={classes.dropdownIcon}/>}
icon={<MoreIcon className={classes.dropdownIcon} />}
options={menuItems}
style={{ focusVisible: classes.focusVisible }}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ import {
ShareAltSvg,
ExclamationCircleInverseSvg,
ZoomInSvg,
InfoCircleSvg } from "@chainsafe/common-components"
import { makeStyles, createStyles, useDoubleClick, useThemeSwitcher } from "@chainsafe/common-theme"
InfoCircleSvg
} from "@chainsafe/common-components"
import { makeStyles, createStyles, useDoubleClick, useThemeSwitcher, useLongPress } from "@chainsafe/common-theme"
import { Form, FormikProvider, useFormik } from "formik"
import CustomModal from "../../../../Elements/CustomModal"
import { t, Trans } from "@lingui/macro"
Expand Down Expand Up @@ -156,7 +157,7 @@ const FileSystemItem = ({
name
},
validationSchema: nameValidator,
onSubmit: (values: {name: string}) => {
onSubmit: (values: { name: string }) => {
const newName = values.name.trim()

newName && handleRename && handleRename(file.cid, newName)
Expand Down Expand Up @@ -327,7 +328,8 @@ const FileSystemItem = ({
)

const [, dragMoveRef, preview] = useDrag(() =>
({ type: DragTypes.MOVABLE_FILE,
({
type: DragTypes.MOVABLE_FILE,
item: () => {
if (selectedCids.includes(file.cid)) {
return { ids: selectedCids }
Expand All @@ -352,7 +354,7 @@ const FileSystemItem = ({
const [{ isOverMove }, dropMoveRef] = useDrop({
accept: DragTypes.MOVABLE_FILE,
canDrop: () => isFolder,
drop: (item: {ids: string[]}) => {
drop: (item: { ids: string[]}) => {
moveItems && moveItems(item.ids, getPathWithFile(currentPath, name))
},
collect: (monitor) => ({
Expand All @@ -379,7 +381,7 @@ const FileSystemItem = ({
}

if (!editing && !isFolder) {
dragMoveRef(fileOrFolderRef)
desktop && dragMoveRef(fileOrFolderRef)
}

const onSingleClick = useCallback(
Expand All @@ -393,14 +395,18 @@ const FileSystemItem = ({
}
} else {
// on mobile
if (isFolder) {
viewFolder && viewFolder(file.cid)
if (selectedCids.length) {
handleAddToSelectedItems(file)
} else {
onFilePreview()
if (isFolder) {
viewFolder && viewFolder(file.cid)
} else {
onFilePreview()
}
}
}
},
[desktop, handleAddToSelectedItems, file, handleSelectItem, isFolder, viewFolder, onFilePreview]
[desktop, handleAddToSelectedItems, file, handleSelectItem, isFolder, viewFolder, onFilePreview, selectedCids.length]
)

const onDoubleClick = useCallback(
Expand All @@ -422,9 +428,15 @@ const FileSystemItem = ({

const { click } = useDoubleClick(onSingleClick, onDoubleClick)

const longPressEvents = useLongPress(() => handleSelectItem(file), onSingleClick)

const onFolderOrFileClicks = (e?: React.MouseEvent) => {
e?.persist()
click(e)
if (!desktop) {
return null
} else {
click(e)
}
}

const itemProps = {
Expand All @@ -444,7 +456,8 @@ const FileSystemItem = ({
preview,
selectedCids,
setEditing,
resetSelectedFiles
resetSelectedFiles,
longPressEvents: !desktop ? longPressEvents : undefined
}

return (
Expand Down
Loading

0 comments on commit 8625789

Please sign in to comment.