Skip to content
This repository was archived by the owner on Sep 19, 2024. It is now read-only.

External node can now be dropped as tree child node as expected #15

Merged
merged 1 commit into from
Feb 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
283 changes: 143 additions & 140 deletions src/tree-node.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { Children, cloneElement } from 'react'
import React, { Children, Component, cloneElement } from 'react'
import { ConnectDropTarget } from 'react-dnd'
import { classnames } from './utils/classnames'
import './tree-node.css'
Expand Down Expand Up @@ -49,164 +49,167 @@ const defaultProps = {
rowDirection: 'ltr',
}

const TreeNode: React.FC<TreeRendererProps> = (props) => {
props = { ...defaultProps, ...props }
const {
children,
listIndex,
swapFrom,
swapLength,
swapDepth,
scaffoldBlockPxWidth,
lowerSiblingCounts,
connectDropTarget,
isOver,
draggedNode,
canDrop,
treeIndex,
rowHeight,
treeId: _treeId, // Delete from otherProps
getPrevRow: _getPrevRow, // Delete from otherProps
node: _node, // Delete from otherProps
path: _path, // Delete from otherProps
rowDirection,
...otherProps
} = props

const rowDirectionClass = rowDirection === 'rtl' ? 'rst__rtl' : undefined

// Construct the scaffold representing the structure of the tree
const scaffoldBlockCount = lowerSiblingCounts.length
const scaffold: any[] = []
for (const [i, lowerSiblingCount] of lowerSiblingCounts.entries()) {
let lineClass = ''
if (lowerSiblingCount > 0) {
// At this level in the tree, the nodes had sibling nodes further down

if (listIndex === 0) {
// Top-left corner of the tree
class TreeNodeComponent extends Component<TreeRendererProps> {
render() {
const props = { ...defaultProps, ...this.props }
const {
children,
listIndex,
swapFrom,
swapLength,
swapDepth,
scaffoldBlockPxWidth,
lowerSiblingCounts,
connectDropTarget,
isOver,
draggedNode,
canDrop,
treeIndex,
rowHeight,
treeId: _treeId, // Delete from otherProps
getPrevRow: _getPrevRow, // Delete from otherProps
node: _node, // Delete from otherProps
path: _path, // Delete from otherProps
rowDirection,
...otherProps
} = props

const rowDirectionClass = rowDirection === 'rtl' ? 'rst__rtl' : undefined

// Construct the scaffold representing the structure of the tree
const scaffoldBlockCount = lowerSiblingCounts.length
const scaffold: any[] = []
for (const [i, lowerSiblingCount] of lowerSiblingCounts.entries()) {
let lineClass = ''
if (lowerSiblingCount > 0) {
// At this level in the tree, the nodes had sibling nodes further down

if (listIndex === 0) {
// Top-left corner of the tree
// +-----+
// | |
// | +--+
// | | |
// +--+--+
lineClass = 'rst__lineHalfHorizontalRight rst__lineHalfVerticalBottom'
} else if (i === scaffoldBlockCount - 1) {
// Last scaffold block in the row, right before the row content
// +--+--+
// | | |
// | +--+
// | | |
// +--+--+
lineClass = 'rst__lineHalfHorizontalRight rst__lineFullVertical'
} else {
// Simply connecting the line extending down to the next sibling on this level
// +--+--+
// | | |
// | | |
// | | |
// +--+--+
lineClass = 'rst__lineFullVertical'
}
} else if (listIndex === 0) {
// Top-left corner of the tree, but has no siblings
// +-----+
// | |
// | +--+
// | | |
// +--+--+
lineClass = 'rst__lineHalfHorizontalRight rst__lineHalfVerticalBottom'
// | |
// +-----+
lineClass = 'rst__lineHalfHorizontalRight'
} else if (i === scaffoldBlockCount - 1) {
// Last scaffold block in the row, right before the row content
// The last or only node in this level of the tree
// +--+--+
// | | |
// | +--+
// | | |
// +--+--+
lineClass = 'rst__lineHalfHorizontalRight rst__lineFullVertical'
} else {
// Simply connecting the line extending down to the next sibling on this level
// +--+--+
// | | |
// | | |
// | | |
// +--+--+
lineClass = 'rst__lineFullVertical'
}
} else if (listIndex === 0) {
// Top-left corner of the tree, but has no siblings
// +-----+
// | |
// | +--+
// | |
// +-----+
lineClass = 'rst__lineHalfHorizontalRight'
} else if (i === scaffoldBlockCount - 1) {
// The last or only node in this level of the tree
// +--+--+
// | | |
// | +--+
// | |
// +-----+
lineClass = 'rst__lineHalfVerticalTop rst__lineHalfHorizontalRight'
}

scaffold.push(
<div
key={`pre_${1 + i}`}
style={{ width: scaffoldBlockPxWidth }}
className={classnames(
'rst__lineBlock',
lineClass,
rowDirectionClass ?? ''
)}
/>
)

if (treeIndex !== listIndex && i === swapDepth) {
// This row has been shifted, and is at the depth of
// the line pointing to the new destination
let highlightLineClass = ''

if (listIndex === swapFrom! + swapLength! - 1) {
// This block is on the bottom (target) line
// This block points at the target block (where the row will go when released)
highlightLineClass = 'rst__highlightBottomLeftCorner'
} else if (treeIndex === swapFrom) {
// This block is on the top (source) line
highlightLineClass = 'rst__highlightTopLeftCorner'
} else {
// This block is between the bottom and top
highlightLineClass = 'rst__highlightLineVertical'
// | |
// +-----+
lineClass = 'rst__lineHalfVerticalTop rst__lineHalfHorizontalRight'
}

const style =
rowDirection === 'rtl'
? {
width: scaffoldBlockPxWidth,
right: scaffoldBlockPxWidth * i,
}
: {
width: scaffoldBlockPxWidth,
left: scaffoldBlockPxWidth * i,
}

scaffold.push(
<div
key={i}
style={style}
key={`pre_${1 + i}`}
style={{ width: scaffoldBlockPxWidth }}
className={classnames(
'rst__absoluteLineBlock',
highlightLineClass,
'rst__lineBlock',
lineClass,
rowDirectionClass ?? ''
)}
/>
)

if (treeIndex !== listIndex && i === swapDepth) {
// This row has been shifted, and is at the depth of
// the line pointing to the new destination
let highlightLineClass = ''

if (listIndex === swapFrom! + swapLength! - 1) {
// This block is on the bottom (target) line
// This block points at the target block (where the row will go when released)
highlightLineClass = 'rst__highlightBottomLeftCorner'
} else if (treeIndex === swapFrom) {
// This block is on the top (source) line
highlightLineClass = 'rst__highlightTopLeftCorner'
} else {
// This block is between the bottom and top
highlightLineClass = 'rst__highlightLineVertical'
}

const style =
rowDirection === 'rtl'
? {
width: scaffoldBlockPxWidth,
right: scaffoldBlockPxWidth * i,
}
: {
width: scaffoldBlockPxWidth,
left: scaffoldBlockPxWidth * i,
}

scaffold.push(
<div
key={i}
style={style}
className={classnames(
'rst__absoluteLineBlock',
highlightLineClass,
rowDirectionClass ?? ''
)}
/>
)
}
}
}

const style =
rowDirection === 'rtl'
? { right: scaffoldBlockPxWidth * scaffoldBlockCount }
: { left: scaffoldBlockPxWidth * scaffoldBlockCount }
const style =
rowDirection === 'rtl'
? { right: scaffoldBlockPxWidth * scaffoldBlockCount }
: { left: scaffoldBlockPxWidth * scaffoldBlockCount }

let calculatedRowHeight = rowHeight
if (typeof rowHeight === 'function') {
calculatedRowHeight = rowHeight(treeIndex, _node, _path)
}
return connectDropTarget(
<div
{...otherProps}
style={{ height: `${calculatedRowHeight}px` }}
className={classnames('rst__node', rowDirectionClass ?? '')}>
{scaffold}

<div className="rst__nodeContent" style={style}>
{Children.map(children, (child: any) =>
cloneElement(child, {
isOver,
canDrop,
draggedNode,
})
)}
let calculatedRowHeight = rowHeight
if (typeof rowHeight === 'function') {
calculatedRowHeight = rowHeight(treeIndex, _node, _path)
}
return connectDropTarget(
<div
{...otherProps}
style={{ height: `${calculatedRowHeight}px` }}
className={classnames('rst__node', rowDirectionClass ?? '')}
ref={(node) => (this.node = node)}>
{scaffold}

<div className="rst__nodeContent" style={style}>
{Children.map(children, (child: any) =>
cloneElement(child, {
isOver,
canDrop,
draggedNode,
})
)}
</div>
</div>
</div>
)
)
}
}

export default TreeNode
export default TreeNodeComponent
3 changes: 1 addition & 2 deletions src/utils/dnd-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,7 @@ const getTargetDepth = (
dragSourceInitialDepth = 0

if (component) {
const rawComponent = component.getDecoratedComponentInstance()
const relativePosition = rawComponent.node.getBoundingClientRect()
const relativePosition = component.node.getBoundingClientRect()
const leftShift =
monitor.getSourceClientOffset().x - relativePosition.left
blocksOffset = Math.round(
Expand Down