Skip to content

Commit

Permalink
feat: support dropping folders on Gltf UI component
Browse files Browse the repository at this point in the history
  • Loading branch information
nicoecheza committed Apr 19, 2023
1 parent 00dea08 commit eb8cdcb
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { useCallback, useState } from 'react'
import { useCallback } from 'react'
import { Menu, Item } from 'react-contexify'
import { useDrop } from 'react-dnd'
import { AiFillDelete as DeleteIcon } from 'react-icons/ai'
import cx from 'classnames'

import { AssetNodeItem } from '../../ProjectAssetExplorer/types'
import { memoize } from '../../../lib/logic/once'
import { TreeNode } from '../../ProjectAssetExplorer/ProjectView'

import { withContextMenu } from '../../../hoc/withContextMenu'
import { WithSdkProps, withSdk } from '../../../hoc/withSdk'
Expand All @@ -18,14 +19,23 @@ import { Container } from '../../Container'
import { TextField } from '../TextField'
import { Props } from './types'
import { fromGltf, toGltf, isValidInput } from './utils'
import { getFullNodePath, isAssetNode } from '../../ProjectAssetExplorer/utils'

const DROP_TYPES = ['project-asset-gltf']

interface IDrop {
value: string;
context: { tree: Map<string, AssetNodeItem> }
context: { tree: Map<string, TreeNode> }
}

const getUniqueLastChild = memoize((node: TreeNode, tree: Map<string, TreeNode>) => {
let _node = node
while ((_node.children || []).length === 1) {
_node = tree.get(_node.children![0])!
}
return _node
})

export default withSdk<Props>(
withContextMenu<WithSdkProps & Props>(({ sdk, entity, contextMenuId }) => {
const { files } = useFileSystem()
Expand All @@ -37,19 +47,37 @@ export default withSdk<Props>(
const getInputProps = useComponentInput(entity, GltfContainer, fromGltf, toGltf, handleInputValidation)

const handleRemove = useCallback(() => GltfContainer.deleteFrom(entity), [])
const handleDrop = useCallback((value: AssetNodeItem) => {
GltfContainer.createOrReplace(entity, { src: value.asset.src })
const handleDrop = useCallback((src: string) => {
GltfContainer.createOrReplace(entity, { src })
}, [])

const [{ isHover }, drop] = useDrop(
() => ({
accept: DROP_TYPES,
drop: ({ value, context }: IDrop, monitor) => {
if (monitor.didDrop()) return
handleDrop(context.tree.get(value)!)
const node = context.tree.get(value)!

if (isAssetNode(node)) return handleDrop(node.asset.src)

const child = getUniqueLastChild(node, context.tree)

// double-checking just to be sure (canDrop already does this...)
if (isAssetNode(child)) {
const path = getFullNodePath(child)
handleDrop(path)
}
},
canDrop: ({ value, context }: IDrop) => {
const node = context.tree.get(value)!
if (node.type === 'folder') {
const child = getUniqueLastChild(node, context.tree)
return isAssetNode(child)
}
return true
},
collect: (monitor) => ({
isHover: monitor.canDrop() && monitor.isOver()
isHover: monitor.isOver() && monitor.canDrop()
})
}),
[files]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type Props = {
const ROOT = 'File System'


type TreeNode = Omit<AssetNode, 'children'> & { children?: string[] }
export type TreeNode = Omit<AssetNode, 'children'> & { children?: string[] }

function ProjectView({ folders }: Props) {
const [open, setOpen] = useState(new Set<string>())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { AssetNode, AssetNodeFolder } from './types'
import { TreeNode } from './ProjectView'
import { AssetNode, AssetNodeFolder, AssetNodeItem } from './types'

export function AssetNodeRootNull(): AssetNodeFolder {
return { name: '', parent: null, type: 'folder', children: [] }
Expand Down Expand Up @@ -44,12 +45,16 @@ export function buildAssetTree(paths: string[]): AssetNodeFolder {
return root
}

export function getFullNodePath(item: AssetNode) {
export function getFullNodePath(item: AssetNode | TreeNode) {
let path = ''
let it = item
while (it.parent !== null && item.name !== '') {
path = item.name + '/' + path
while (it.parent) {
path = '/' + it.name + path
it = it.parent
}
return path
}

export function isAssetNode(node: AssetNode | TreeNode): node is AssetNodeItem {
return node.type === 'asset'
}
6 changes: 3 additions & 3 deletions packages/@dcl/inspector/src/lib/logic/once.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
export function memoize<K extends object, V>(cb: (a: K) => V): (a: K) => V {
export function memoize<K extends object, P, V>(cb: (a: K, ...params: P[]) => V): (a: K, ...params: P[]) => V {
const memoized = new WeakMap<K, V>()
return (a: K) => {
return (a: K, ...params: P[]) => {
if (!memoized.has(a)) {
const ret = cb(a)
const ret = cb(a, ...params)
memoized.set(a, ret)
return ret
}
Expand Down

0 comments on commit eb8cdcb

Please sign in to comment.