Simplifying drag and drop for sorting with my own hook
This commit is contained in:
parent
13b8e40f98
commit
f1673dcc85
5 changed files with 39 additions and 89 deletions
|
@ -1,8 +1,7 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
import React, {useRef} from 'react'
|
||||
import React from 'react'
|
||||
import {FormattedMessage, injectIntl, IntlShape} from 'react-intl'
|
||||
import {useDrag, useDrop} from 'react-dnd'
|
||||
|
||||
import {IPropertyTemplate} from '../../blocks/board'
|
||||
import {Card} from '../../blocks/card'
|
||||
|
@ -16,6 +15,7 @@ import DuplicateIcon from '../../widgets/icons/duplicate'
|
|||
import OptionsIcon from '../../widgets/icons/options'
|
||||
import Menu from '../../widgets/menu'
|
||||
import MenuWrapper from '../../widgets/menuWrapper'
|
||||
import useSortable from '../../hooks/sortable'
|
||||
|
||||
import ImageElement from '../content/imageElement'
|
||||
import ContentElement from '../content/contentElement'
|
||||
|
@ -35,23 +35,7 @@ type Props = {
|
|||
|
||||
const GalleryCard = React.memo((props: Props) => {
|
||||
const {cardTree} = props
|
||||
const cardRef = useRef<HTMLDivElement>(null)
|
||||
const [{isDragging}, drag] = useDrag(() => ({
|
||||
type: 'card',
|
||||
item: cardTree.card,
|
||||
collect: (monitor) => ({
|
||||
isDragging: monitor.isDragging(),
|
||||
}),
|
||||
}), [cardTree, props.onDrop])
|
||||
const [{isOver}, drop] = useDrop(() => ({
|
||||
accept: 'card',
|
||||
collect: (monitor) => ({
|
||||
isOver: monitor.isOver(),
|
||||
}),
|
||||
drop: (item: Card) => {
|
||||
props.onDrop(item, cardTree.card)
|
||||
},
|
||||
}), [cardTree, props.onDrop])
|
||||
const [isDragging, isOver, cardRef] = useSortable('card', cardTree.card, props.onDrop)
|
||||
|
||||
const visiblePropertyTemplates = props.visiblePropertyTemplates || []
|
||||
|
||||
|
@ -62,8 +46,6 @@ const GalleryCard = React.memo((props: Props) => {
|
|||
className += ' dragover'
|
||||
}
|
||||
|
||||
drop(drag(cardRef))
|
||||
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
import React, {useRef} from 'react'
|
||||
import React from 'react'
|
||||
import {injectIntl, IntlShape} from 'react-intl'
|
||||
import {useDrag, useDrop} from 'react-dnd'
|
||||
|
||||
import {IPropertyTemplate} from '../../blocks/board'
|
||||
import {Card} from '../../blocks/card'
|
||||
|
@ -13,6 +12,7 @@ import DuplicateIcon from '../../widgets/icons/duplicate'
|
|||
import OptionsIcon from '../../widgets/icons/options'
|
||||
import Menu from '../../widgets/menu'
|
||||
import MenuWrapper from '../../widgets/menuWrapper'
|
||||
import useSortable from '../../hooks/sortable'
|
||||
|
||||
import './kanbanCard.scss'
|
||||
import PropertyValueElement from '../propertyValueElement'
|
||||
|
@ -28,33 +28,14 @@ type Props = {
|
|||
}
|
||||
|
||||
const KanbanCard = React.memo((props: Props) => {
|
||||
const cardRef = useRef<HTMLDivElement>(null)
|
||||
const {card, intl} = props
|
||||
const [{isDragging}, drag] = useDrag(() => ({
|
||||
type: 'card',
|
||||
item: card,
|
||||
collect: (monitor) => ({
|
||||
isDragging: monitor.isDragging(),
|
||||
}),
|
||||
}), [card])
|
||||
const [{isOver}, drop] = useDrop(() => ({
|
||||
accept: 'card',
|
||||
collect: (monitor) => ({
|
||||
isOver: monitor.isOver(),
|
||||
}),
|
||||
drop: (item: Card) => {
|
||||
props.onDrop(item, card)
|
||||
},
|
||||
}), [card, props.onDrop])
|
||||
|
||||
const [isDragging, isOver, cardRef] = useSortable('card', card, props.onDrop)
|
||||
const visiblePropertyTemplates = props.visiblePropertyTemplates || []
|
||||
let className = props.isSelected ? 'KanbanCard selected' : 'KanbanCard'
|
||||
if (isOver) {
|
||||
className += ' dragover'
|
||||
}
|
||||
|
||||
drop(drag(cardRef))
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={props.readonly ? () => null : cardRef}
|
||||
|
|
|
@ -10,6 +10,7 @@ import SortDownIcon from '../../widgets/icons/sortDown'
|
|||
import SortUpIcon from '../../widgets/icons/sortUp'
|
||||
import MenuWrapper from '../../widgets/menuWrapper'
|
||||
import Label from '../../widgets/label'
|
||||
import useSortable from '../../hooks/sortable'
|
||||
|
||||
import HorizontalGrip from './horizontalGrip'
|
||||
|
||||
|
@ -23,38 +24,16 @@ type Props = {
|
|||
boardTree: BoardTree
|
||||
template: IPropertyTemplate
|
||||
offset: number
|
||||
onDrop?: (template: IPropertyTemplate, container: IPropertyTemplate) => void
|
||||
onDrop: (template: IPropertyTemplate, container: IPropertyTemplate) => void
|
||||
}
|
||||
|
||||
const TableHeader = React.memo((props: Props): JSX.Element => {
|
||||
const columnRef = useRef<HTMLDivElement>(null)
|
||||
const [{isDragging}, drag] = useDrag(() => ({
|
||||
type: 'column',
|
||||
item: props.template,
|
||||
collect: (monitor) => ({
|
||||
isDragging: monitor.isDragging(),
|
||||
}),
|
||||
}))
|
||||
const [{isOver}, drop] = useDrop(() => ({
|
||||
accept: 'column',
|
||||
collect: (monitor) => ({
|
||||
isOver: monitor.isOver(),
|
||||
}),
|
||||
drop: (item: IPropertyTemplate) => {
|
||||
props.onDrop && props.onDrop(item, props.template)
|
||||
},
|
||||
}))
|
||||
const [isDragging, isOver, columnRef] = useSortable('column', props.template, props.onDrop)
|
||||
|
||||
const columnWidth = (templateId: string): number => {
|
||||
return Math.max(Constants.minColumnWidth, (props.boardTree.activeView.columnWidths[templateId] || 0) + props.offset)
|
||||
}
|
||||
|
||||
if (props.template.id === Constants.titleColumnId) {
|
||||
drop(columnRef)
|
||||
} else {
|
||||
drop(drag(columnRef))
|
||||
}
|
||||
|
||||
let className = 'octo-table-cell header-cell'
|
||||
if (isOver) {
|
||||
className += ' dragover'
|
||||
|
@ -64,7 +43,7 @@ const TableHeader = React.memo((props: Props): JSX.Element => {
|
|||
<div
|
||||
className={className}
|
||||
style={{overflow: 'unset', width: columnWidth(props.template.id), opacity: isDragging ? 0.5 : 1}}
|
||||
ref={props.onDrop ? columnRef : () => null}
|
||||
ref={props.template.id === Constants.titleColumnId ? () => null : columnRef}
|
||||
>
|
||||
<MenuWrapper disabled={props.readonly}>
|
||||
<Label>
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
// See LICENSE.txt for license information.
|
||||
import React, {useState, useRef, useEffect} from 'react'
|
||||
import {FormattedMessage} from 'react-intl'
|
||||
import {useDrop, useDrag} from 'react-dnd'
|
||||
|
||||
import {Card} from '../../blocks/card'
|
||||
import {Constants} from '../../constants'
|
||||
|
@ -10,6 +9,7 @@ import mutator from '../../mutator'
|
|||
import {BoardTree} from '../../viewModel/boardTree'
|
||||
import Button from '../../widgets/buttons/button'
|
||||
import Editable from '../../widgets/editable'
|
||||
import useSortable from '../../hooks/sortable'
|
||||
|
||||
import PropertyValueElement from '../propertyValueElement'
|
||||
import './tableRow.scss'
|
||||
|
@ -29,25 +29,8 @@ type Props = {
|
|||
const TableRow = React.memo((props: Props) => {
|
||||
const titleRef = useRef<Editable>(null)
|
||||
const [title, setTitle] = useState(props.card.title)
|
||||
const cardRef = useRef<HTMLDivElement>(null)
|
||||
const {card} = props
|
||||
const [{isDragging}, drag] = useDrag(() => ({
|
||||
type: 'card',
|
||||
item: card,
|
||||
collect: (monitor) => ({
|
||||
isDragging: monitor.isDragging(),
|
||||
}),
|
||||
}), [card])
|
||||
|
||||
const [{isOver}, drop] = useDrop(() => ({
|
||||
accept: 'card',
|
||||
collect: (monitor) => ({
|
||||
isOver: monitor.isOver(),
|
||||
}),
|
||||
drop: (item: Card) => {
|
||||
props.onDrop(item, card)
|
||||
},
|
||||
}), [card, props.onDrop])
|
||||
const [isDragging, isOver, cardRef] = useSortable('card', card, props.onDrop)
|
||||
|
||||
useEffect(() => {
|
||||
if (props.focusOnMount) {
|
||||
|
@ -67,8 +50,6 @@ const TableRow = React.memo((props: Props) => {
|
|||
className += ' dragover'
|
||||
}
|
||||
|
||||
drop(drag(cardRef))
|
||||
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
|
|
27
webapp/src/hooks/sortable.tsx
Normal file
27
webapp/src/hooks/sortable.tsx
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
import React, {useRef} from 'react'
|
||||
import {useDrag, useDrop} from 'react-dnd'
|
||||
|
||||
export default function useSortable(itemType: string, item: any, handler: (src: any, st: any) => void): [boolean, boolean, React.RefObject<HTMLDivElement>] {
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
const [{isDragging}, drag] = useDrag(() => ({
|
||||
type: itemType,
|
||||
item,
|
||||
collect: (monitor) => ({
|
||||
isDragging: monitor.isDragging(),
|
||||
}),
|
||||
}), [itemType, item])
|
||||
const [{isOver}, drop] = useDrop(() => ({
|
||||
accept: itemType,
|
||||
collect: (monitor) => ({
|
||||
isOver: monitor.isOver(),
|
||||
}),
|
||||
drop: (dragItem: any) => {
|
||||
handler(dragItem, item)
|
||||
},
|
||||
}), [item, handler])
|
||||
|
||||
drop(drag(ref))
|
||||
return [isDragging, isOver, ref]
|
||||
}
|
Loading…
Reference in a new issue