From eccbdf16a7b136256f49ec66617a33ab8a93285b Mon Sep 17 00:00:00 2001 From: Al-Ameen Ogundiran Date: Tue, 13 Jun 2023 14:25:40 +0100 Subject: [PATCH 1/6] add drag and drop file to folder support --- package.json | 8 ++- src/components/FolderTree/FolderTree.jsx | 19 ++++++- src/components/SandBox/SandBox.jsx | 11 +++- src/components/TreeNode/TreeNode.jsx | 26 ++++++++- src/utils/dnd.js | 7 +++ yarn.lock | 72 +++++++++++++++++++++++- 6 files changed, 134 insertions(+), 9 deletions(-) create mode 100644 src/utils/dnd.js diff --git a/package.json b/package.json index 3eba59b3..3068a320 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "license": "MIT", "private": false, "scripts": { - "prebuild": "del \"dist/\"", + "prebuild": "rimraf dist", "build": "webpack --config config/webpack.prod.config.js", "start": "cross-env NODE_ENV=development node scripts/dev-server.js", "lint": "eslint src/ --ext .js,.jsx", @@ -99,10 +99,14 @@ }, "peerDependencies": { "react": "^16.8.0 || ^17", - "react-dom": "^16.8.0 || ^17" + "react-dom": "^16.8.0 || ^17", + "react-dnd": "^16.0.1", + "react-dnd-html5-backend": "^16.0.1" }, "dependencies": { "prop-types": "^15.7.2", + "react-dnd": "^16.0.1", + "react-dnd-html5-backend": "^16.0.1", "react-icons": "^4.1.0", "use-tree-state": "1.0.0" } diff --git a/src/components/FolderTree/FolderTree.jsx b/src/components/FolderTree/FolderTree.jsx index ceb986a4..c868da00 100644 --- a/src/components/FolderTree/FolderTree.jsx +++ b/src/components/FolderTree/FolderTree.jsx @@ -1,4 +1,6 @@ import React from 'react'; +import { DndProvider } from 'react-dnd'; +import { HTML5Backend } from 'react-dnd-html5-backend'; import PropTypes from 'prop-types'; import useTreeState, { testData, @@ -28,6 +30,10 @@ const FolderTree = ({ debug = false, searchData = null, showSearchData = false, + dndConfig = { + onDrop: null, + backend: null, + }, }) => { const options = { initCheckedStatus, @@ -56,6 +62,7 @@ const FolderTree = ({ debug, searchData, showSearchData, + dndConfig, }; /* ---------- @@ -69,9 +76,11 @@ const FolderTree = ({ return (
- - - + + + + +
); }; @@ -104,6 +113,10 @@ FolderTree.propTypes = { debug: PropTypes.bool, searchData: PropTypes.object, showSearchData: PropTypes.bool, + dndConfig: PropTypes.shape({ + backend: PropTypes.func, + onDrop: PropTypes.func, + }), }; export { diff --git a/src/components/SandBox/SandBox.jsx b/src/components/SandBox/SandBox.jsx index 4b8909e3..ea8da21c 100644 --- a/src/components/SandBox/SandBox.jsx +++ b/src/components/SandBox/SandBox.jsx @@ -1,4 +1,5 @@ import React, { useEffect, useState } from 'react'; +import PropTypes from 'prop-types'; import FolderTree, { testData } from '../FolderTree/FolderTree'; const makeId = (length) => { @@ -63,7 +64,7 @@ const parseTestData = (node) => { }; /* eslint-disable */ -const SandBox = () => { +const SandBox = ({ dndConfig }) => { const onTreeStateChange = (state, e) => console.log({ state, e }); const [tree, setTree] = useState(null); @@ -79,6 +80,7 @@ const SandBox = () => { !!tree && (
{ @@ -110,4 +112,11 @@ const SandBox = () => { ); }; +SandBox.propTypes = { + dndConfig: PropTypes.shape({ + backend: PropTypes.func, + onDrop: PropTypes.func, + }), +}; + export default SandBox; diff --git a/src/components/TreeNode/TreeNode.jsx b/src/components/TreeNode/TreeNode.jsx index ba9e20f7..8a0dc4af 100644 --- a/src/components/TreeNode/TreeNode.jsx +++ b/src/components/TreeNode/TreeNode.jsx @@ -2,6 +2,8 @@ import React, { useContext, useState, } from 'react'; +import { useDrag, useDrop } from 'react-dnd'; +import { NativeTypes } from 'react-dnd-html5-backend'; import PropTypes from 'prop-types'; import { AiFillCaretRight, @@ -25,6 +27,7 @@ import { iconClassName, getDefaultIcon, } from '../../utils/iconUtils'; +import { FileTreeDragTypes } from '../../utils/dnd'; const TreeNode = ({ path, @@ -51,6 +54,7 @@ const TreeNode = ({ onIconClick, showCheckbox, readOnly, + dndConfig: { onDrop }, searchData, showSearchData, @@ -58,6 +62,16 @@ const TreeNode = ({ debug, } = useContext(ConfigContext); + const [_, drop] = useDrop(() => ({ + accept: [FileTreeDragTypes.TREE_NODE, NativeTypes.FILE], + drop: item => { + onDrop?.(item); + }, + collect: monitor => ({ + isOver: monitor.isOver(), + }), + }), [onDrop]); + const isFolder = !!children; let matchCount = 0; @@ -80,6 +94,14 @@ const TreeNode = ({ ...restData, }; + const [__, drag] = useDrag({ + type: FileTreeDragTypes.TREE_NODE, + item: nodeData, + collect: (monitor) => ({ + isDragging: monitor.isDragging(), + }), + }); + const level = path.length; const offsetSize = !isFolder ? 0 : iconSize; @@ -245,6 +267,7 @@ const TreeNode = ({ return ( <>
Date: Tue, 13 Jun 2023 14:26:06 +0100 Subject: [PATCH 2/6] add fallback to jsx-runtime in dev mode --- config/webpack.config.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/webpack.config.js b/config/webpack.config.js index b3851869..eba0ca92 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -20,6 +20,10 @@ module.exports = { resolve: { // our code can resolve 'xxx' instead of writing 'xxx.jsx' extensions: ['*', '.js', '.jsx'], + fallback: { + 'react/jsx-runtime': 'react/jsx-runtime.js', + 'react/jsx-dev-runtime': 'react/jsx-dev-runtime.js', + }, }, module: { // For every file that match regex in 'test', webpack pipes the code through to loaders From d2506fe9b7fd0ec4113df4fb9973050ffef5ffb3 Mon Sep 17 00:00:00 2001 From: Al-Ameen Ogundiran Date: Tue, 13 Jun 2023 14:26:19 +0100 Subject: [PATCH 3/6] add nvmrc version --- .nvmrc | 1 + 1 file changed, 1 insertion(+) create mode 100644 .nvmrc diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..19c7bdba --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +16 \ No newline at end of file From c4137a2a5b3852b6916a09ccf7ee06a7a6c442de Mon Sep 17 00:00:00 2001 From: Al-Ameen Ogundiran Date: Tue, 13 Jun 2023 14:30:23 +0100 Subject: [PATCH 4/6] bump package version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3068a320..8d6dd2e7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "script-custom-react-folder-tree", - "version": "5.0.11", + "version": "5.1.0", "description": "customizable react folder tree library", "main": "dist/react-folder-tree.bundle.js", "typings": "index.d.ts", From 137ade81f2e2b29535c8a5888315803eb5341def Mon Sep 17 00:00:00 2001 From: Al-Ameen Ogundiran Date: Wed, 14 Jun 2023 13:12:26 +0100 Subject: [PATCH 5/6] fix react-dnd test --- package.json | 4 ++-- src/components/TreeNode/TreeNode.jsx | 6 ++++-- src/components/TreeNode/TreeNode.test.js | 5 +++++ src/test/jest-setup.js | 14 ++++++++++++++ 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 8d6dd2e7..f3b7aaab 100644 --- a/package.json +++ b/package.json @@ -99,9 +99,9 @@ }, "peerDependencies": { "react": "^16.8.0 || ^17", - "react-dom": "^16.8.0 || ^17", "react-dnd": "^16.0.1", - "react-dnd-html5-backend": "^16.0.1" + "react-dnd-html5-backend": "^16.0.1", + "react-dom": "^16.8.0 || ^17" }, "dependencies": { "prop-types": "^15.7.2", diff --git a/src/components/TreeNode/TreeNode.jsx b/src/components/TreeNode/TreeNode.jsx index 8a0dc4af..150fd047 100644 --- a/src/components/TreeNode/TreeNode.jsx +++ b/src/components/TreeNode/TreeNode.jsx @@ -54,7 +54,7 @@ const TreeNode = ({ onIconClick, showCheckbox, readOnly, - dndConfig: { onDrop }, + dndConfig, searchData, showSearchData, @@ -62,6 +62,8 @@ const TreeNode = ({ debug, } = useContext(ConfigContext); + const { onDrop } = dndConfig || {}; + const [_, drop] = useDrop(() => ({ accept: [FileTreeDragTypes.TREE_NODE, NativeTypes.FILE], drop: item => { @@ -97,7 +99,7 @@ const TreeNode = ({ const [__, drag] = useDrag({ type: FileTreeDragTypes.TREE_NODE, item: nodeData, - collect: (monitor) => ({ + collect: monitor => ({ isDragging: monitor.isDragging(), }), }); diff --git a/src/components/TreeNode/TreeNode.test.js b/src/components/TreeNode/TreeNode.test.js index 2c642353..f533b873 100644 --- a/src/components/TreeNode/TreeNode.test.js +++ b/src/components/TreeNode/TreeNode.test.js @@ -13,6 +13,10 @@ const deleteNode = jest.fn(); const addNode = jest.fn(); const toggleOpen = jest.fn(); const onNameClick = jest.fn(); +const dndConfig = { + onDrop: null, + backend: null, +}; const render = ({ iconComponents = {}, @@ -39,6 +43,7 @@ const render = ({ indentPixels, showCheckbox, readOnly, + dndConfig, }; node = mount(( diff --git a/src/test/jest-setup.js b/src/test/jest-setup.js index 76b0ba5d..4df856d5 100644 --- a/src/test/jest-setup.js +++ b/src/test/jest-setup.js @@ -1,5 +1,19 @@ +import React from 'react'; import { configure } from 'enzyme'; // import Adapter from 'enzyme-adapter-react-16'; import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; configure({ adapter: new Adapter() }); + +// Mock implementation for the DndProvider component +const DndProvider = ({ children }) =>
{children}
; + +jest.mock('react-dnd', () => ({ + useDrag: jest.fn((...args) => [{ isDragging: false }, jest.fn()]), + useDrop: jest.fn((...args) => [{ isOver: false }, jest.fn()]), + DndProvider, +})); + +jest.mock('react-dnd-html5-backend', () => ({ + HTML5Backend: jest.fn(), +})); From dd9cfef7715d22cdf3ae4e9274333d1dd8eb953e Mon Sep 17 00:00:00 2001 From: Al-Ameen Ogundiran Date: Wed, 14 Jun 2023 13:13:12 +0100 Subject: [PATCH 6/6] add eol --- .nvmrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nvmrc b/.nvmrc index 19c7bdba..b6a7d89c 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -16 \ No newline at end of file +16