Merge pull request #2620 from iamsethsamuel/drag-n-drop
files can now be dragged and droppull/2747/head^2
commit
574cd0b833
@ -0,0 +1,4 @@ |
||||
|
||||
const nxPreset = require('@nrwl/jest/preset'); |
||||
|
||||
module.exports = { ...nxPreset } |
@ -0,0 +1,4 @@ |
||||
{ |
||||
"presets": ["@nrwl/react/babel"], |
||||
"plugins": [] |
||||
} |
@ -0,0 +1,19 @@ |
||||
{ |
||||
"env": { |
||||
"browser": true, |
||||
"es6": true |
||||
}, |
||||
"extends": "../../../.eslintrc.json", |
||||
"globals": { |
||||
"Atomics": "readonly", |
||||
"SharedArrayBuffer": "readonly" |
||||
}, |
||||
"parserOptions": { |
||||
"ecmaVersion": 11, |
||||
"sourceType": "module" |
||||
}, |
||||
"rules": { |
||||
"no-unused-vars": "off", |
||||
"@typescript-eslint/no-unused-vars": "error" |
||||
} |
||||
} |
@ -0,0 +1,7 @@ |
||||
# remix-ui-drag-n-drop |
||||
|
||||
This library was generated with [Nx](https://nx.dev). |
||||
|
||||
## Running unit tests |
||||
|
||||
Run `nx test remix-ui-drag-n-drop` to execute the unit tests via [Jest](https://jestjs.io). |
@ -0,0 +1,9 @@ |
||||
module.exports = { |
||||
displayName: 'remix-ui-drag-n-drop', |
||||
preset: '../../../jest.preset.js', |
||||
transform: { |
||||
'^.+\\.[tj]sx?$': 'babel-jest' |
||||
}, |
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], |
||||
coverageDirectory: '../../../coverage/libs/remix-ui/drag-n-drop' |
||||
}; |
@ -0,0 +1,2 @@ |
||||
|
||||
export * from './lib/remix-ui-drag-n-drop'; |
@ -0,0 +1,112 @@ |
||||
import React, { |
||||
createContext, |
||||
ReactNode, |
||||
useContext, |
||||
useRef, |
||||
useState, |
||||
} from "react"; |
||||
|
||||
|
||||
export interface FileType { |
||||
path: string, |
||||
name: string, |
||||
isDirectory: boolean, |
||||
type: 'folder' | 'file' | 'gist', |
||||
child?: File[] |
||||
} |
||||
|
||||
interface MoveContextType { |
||||
dragged: string; |
||||
isDraggable?: boolean; |
||||
moveFile: (dest: string, dragged: string) => void; |
||||
currentlyMoved: (path: string) => void; |
||||
} |
||||
interface DraggableType { |
||||
children: ReactNode; |
||||
file: FileType; |
||||
isDraggable?: boolean; |
||||
expandedPath: string[]; |
||||
handleClickFolder: (path: string, type: string) => void; |
||||
} |
||||
|
||||
interface DragType { |
||||
children: ReactNode; |
||||
onFileMoved: (dest: string, dragged: string) => void; |
||||
} |
||||
|
||||
export const MoveContext = createContext<MoveContextType>({ |
||||
dragged: "", |
||||
moveFile: () => {}, |
||||
currentlyMoved: () => {}, |
||||
}); |
||||
|
||||
export const Drag = (props: DragType) => { |
||||
const [dragged, setDragged] = useState<string>(""); |
||||
|
||||
return ( |
||||
<MoveContext.Provider |
||||
value={{ |
||||
dragged: dragged, |
||||
moveFile: props.onFileMoved, |
||||
currentlyMoved: (path) => { |
||||
setDragged(() => path); |
||||
}, |
||||
}} |
||||
> |
||||
{props.children} |
||||
</MoveContext.Provider> |
||||
); |
||||
}; |
||||
|
||||
export const Draggable = (props: DraggableType) => { |
||||
const dragRef = useRef<HTMLSpanElement | null>(null), |
||||
file = props.file, |
||||
context = useContext(MoveContext); |
||||
|
||||
const handleDrop = (event: React.DragEvent<HTMLSpanElement>) => { |
||||
event.preventDefault(); |
||||
|
||||
if (file.isDirectory) { |
||||
context.moveFile(file.path, context.dragged); |
||||
} |
||||
}; |
||||
|
||||
const handleDragover = (event: React.DragEvent<HTMLSpanElement>) => { |
||||
//Checks if the folder is opened
|
||||
event.preventDefault(); |
||||
if (file.isDirectory && !props.expandedPath.includes(file.path)) { |
||||
props.handleClickFolder(file.path, file.type); |
||||
} |
||||
}; |
||||
const handleDrag = () => { |
||||
if (context.dragged !== file.path) { |
||||
context.currentlyMoved(file.path); |
||||
} |
||||
}; |
||||
|
||||
if (props.isDraggable) { |
||||
return <>{props.children}</>; |
||||
} |
||||
|
||||
return ( |
||||
<span |
||||
ref={dragRef} |
||||
draggable |
||||
onDrop={(event) => { |
||||
handleDrop(event); |
||||
}} |
||||
onDragStart={() => { |
||||
if (file) { |
||||
handleDrag(); |
||||
} |
||||
}} |
||||
onDragOver={(event) => { |
||||
if (file && file.isDirectory) { |
||||
handleDragover(event); |
||||
} |
||||
}} |
||||
> |
||||
{props.children} |
||||
</span> |
||||
); |
||||
}; |
@ -0,0 +1,23 @@ |
||||
{ |
||||
"extends": "../../../tsconfig.base.json", |
||||
"compilerOptions": { |
||||
"jsx": "react-jsx", |
||||
"allowJs": true, |
||||
"esModuleInterop": true, |
||||
"allowSyntheticDefaultImports": true, |
||||
"forceConsistentCasingInFileNames": true, |
||||
"strict": true, |
||||
"noImplicitReturns": true, |
||||
"noFallthroughCasesInSwitch": true |
||||
}, |
||||
"files": [], |
||||
"include": [], |
||||
"references": [ |
||||
{ |
||||
"path": "./tsconfig.lib.json" |
||||
}, |
||||
{ |
||||
"path": "./tsconfig.spec.json" |
||||
} |
||||
] |
||||
} |
@ -0,0 +1,13 @@ |
||||
{ |
||||
"extends": "./tsconfig.json", |
||||
"compilerOptions": { |
||||
"outDir": "../../../dist/out-tsc", |
||||
"types": ["node"] |
||||
}, |
||||
"files": [ |
||||
"../../../node_modules/@nrwl/react/typings/cssmodule.d.ts", |
||||
"../../../node_modules/@nrwl/react/typings/image.d.ts" |
||||
], |
||||
"exclude": ["**/*.spec.ts", "**/*.spec.tsx"], |
||||
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] |
||||
} |
@ -0,0 +1,15 @@ |
||||
{ |
||||
"extends": "./tsconfig.json", |
||||
"compilerOptions": { |
||||
"outDir": "../../../dist/out-tsc", |
||||
"module": "commonjs", |
||||
"types": ["jest", "node"] |
||||
}, |
||||
"include": [ |
||||
"**/*.spec.ts", |
||||
"**/*.spec.tsx", |
||||
"**/*.spec.js", |
||||
"**/*.spec.jsx", |
||||
"**/*.d.ts" |
||||
] |
||||
} |
Loading…
Reference in new issue