drag and drop is now a library

pull/2620/head
Seth Samuel 2 years ago
parent 1e875da4c2
commit a1b02f3756
  1. 2
      jest.config.js
  2. 4
      jest.preset.js
  3. 3
      libs/remix-ui/draggable/.babelrc
  4. 33
      libs/remix-ui/draggable/.eslintrc.json
  5. 10
      libs/remix-ui/draggable/README.md
  6. 14
      libs/remix-ui/draggable/jest.config.js
  7. 1
      libs/remix-ui/draggable/src/index.ts
  8. 7
      libs/remix-ui/draggable/src/lib/remix-ui-draggable.spec.ts
  9. 104
      libs/remix-ui/draggable/src/lib/remix-ui-draggable.tsx
  10. 19
      libs/remix-ui/draggable/tsconfig.json
  11. 11
      libs/remix-ui/draggable/tsconfig.lib.json
  12. 15
      libs/remix-ui/draggable/tsconfig.spec.json
  13. 20
      libs/remix-ui/workspace/src/lib/components/file-explorer.tsx
  14. 2
      libs/remix-ui/workspace/src/lib/contexts/index.ts
  15. 7
      libs/remix-ui/workspace/src/lib/providers/FileSystemProvider.tsx
  16. 1
      libs/remix-ui/workspace/src/lib/types/index.ts
  17. 131
      tsconfig.base.json

@ -21,5 +21,5 @@ module.exports = {
"<rootDir>/../../dist/libs/remix-ws-templates/src/index.js" "<rootDir>/../../dist/libs/remix-ws-templates/src/index.js"
, ,
"@remix-project/remixd": "<rootDir>/../../dist/libs/remixd/index.js" "@remix-project/remixd": "<rootDir>/../../dist/libs/remixd/index.js"
} },"projects": "<rootDir>/libs/remix-ui/draggable"
}; };

@ -0,0 +1,4 @@
const nxPreset = require('@nrwl/jest/preset');
module.exports = { ...nxPreset }

@ -0,0 +1,3 @@
{
"presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]]
}

@ -0,0 +1,33 @@
{
"extends": [
"../../../.eslintrc.json"
],
"ignorePatterns": [
"!**/*"
],
"overrides": [
{
"files": [
"*.ts",
"*.tsx",
"*.js",
"*.jsx"
],
"rules": {}
},
{
"files": [
"*.ts",
"*.tsx"
],
"rules": {}
},
{
"files": [
"*.js",
"*.jsx"
],
"rules": {}
}
]
}

@ -0,0 +1,10 @@
# remix-ui-draggable
This library was generated with [Nx](https://nx.dev).
## Running unit tests
Run `nx test remix-ui-draggable` to execute the unit tests via [Jest](https://jestjs.io).

@ -0,0 +1,14 @@
module.exports = {
displayName: 'remix-ui-draggable',
preset: '../../../jest.preset.js',
globals: {
'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json',
}
},
transform: {
'^.+\\.[tj]sx?$': 'ts-jest'
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: '../../../coverage/libs/remix-ui/draggable'
};

@ -0,0 +1 @@
export * from './lib/remix-ui-draggable';

@ -0,0 +1,7 @@
import { remixUiDraggable } from './remix-ui-draggable';
describe('remixUiDraggable', () => {
it('should work', () => {
expect(remixUiDraggable()).toEqual('remix-ui-draggable');
})
})

@ -0,0 +1,104 @@
import { FileType } from "libs/remix-ui/workspace/src/lib/types";
import React, {
createContext,
ReactNode,
useContext,
useRef,
useState,
} from "react";
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>(),
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={(event) => {
if (file) {
handleDrag();
}
}}
onDragOver={(event) => {
if (file && file.isDirectory) {
handleDragover(event);
}
}}
>
{props.children}
</span>
);
};

@ -0,0 +1,19 @@
{
"extends": "../../../tsconfig.base.json",
"files": [],
"include": [],
"compilerOptions": {
"jsx": "react",
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
},
"references": [
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}

@ -0,0 +1,11 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "commonjs",
"outDir": "../../../dist/out-tsc",
"declaration": true,
"types": ["node"]
},
"exclude": ["**/*.spec.ts"],
"include": ["**/*.ts", "src/lib/remix-ui-draggable.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"
]
}

@ -10,7 +10,7 @@ import '../css/file-explorer.css'
import { checkSpecialChars, extractNameFromKey, extractParentFromKey, joinPath } from '@remix-ui/helper' import { checkSpecialChars, extractNameFromKey, extractParentFromKey, joinPath } from '@remix-ui/helper'
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
import { FileRender } from './file-render' import { FileRender } from './file-render'
import { MoveContext } from '../contexts' import { Drag } from '@remix-project/remix-ui/draggable'
export const FileExplorer = (props: FileExplorerProps) => { export const FileExplorer = (props: FileExplorerProps) => {
const { name, contextMenuItems, removedContextMenuItems, files, fileState } = props const { name, contextMenuItems, removedContextMenuItems, files, fileState } = props
@ -411,21 +411,16 @@ export const FileExplorer = (props: FileExplorerProps) => {
props.dispatchHandleExpandPath(expandPath) props.dispatchHandleExpandPath(expandPath)
} }
const handleFileMove = (dest: string, dragged:string)=>{
return (
<MoveContext.Provider value={{
dragged: dragged,
moveFile: ( dest: string) => {
try { try {
props.dispatchMoveFile(dragged, dest) props.dispatchMoveFile(dragged, dest)
} catch (error) { } catch (error) {
props.modal('Moving File Failed', 'Unexpected error while moving file: ' + dragged, 'Close', async () => {}) props.modal('Moving File Failed', 'Unexpected error while moving file: ' + dragged, 'Close', async () => {})
} }
}, }
currentlyMoved:(path)=>{
setDragged(path) return (
} <Drag onFileMoved={handleFileMove}>
}}>
<div ref={treeRef} tabIndex={0} style={{ outline: "none" }}> <div ref={treeRef} tabIndex={0} style={{ outline: "none" }}>
<TreeView id='treeView'> <TreeView id='treeView'>
<TreeViewItem id="treeViewItem" <TreeViewItem id="treeViewItem"
@ -490,7 +485,8 @@ export const FileExplorer = (props: FileExplorerProps) => {
/> />
} }
</div> </div>
</MoveContext.Provider> ) </Drag>
)
} }
export default FileExplorer export default FileExplorer

@ -32,6 +32,8 @@ export const FileSystemContext = createContext<{
dispatchHandleRestoreBackup: () => Promise<void> dispatchHandleRestoreBackup: () => Promise<void>
dispatchMoveFile: (src: string, dest: string) => Promise<void>, dispatchMoveFile: (src: string, dest: string) => Promise<void>,
dispatchCloneRepository: (url: string) => Promise<void> dispatchCloneRepository: (url: string) => Promise<void>
dispatchMoveFile: (src: string, dest: string) => Promise<void>,
}>(null) }>(null)
interface MoveContextType{ interface MoveContextType{

@ -5,7 +5,9 @@ import { Toaster } from '@remix-ui/toaster' // eslint-disable-line
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
import { FileSystemContext } from '../contexts' import { FileSystemContext } from '../contexts'
import { browserReducer, browserInitialState } from '../reducers/workspace' import { browserReducer, browserInitialState } from '../reducers/workspace'
import { initWorkspace, fetchDirectory, removeInputField, deleteWorkspace, clearPopUp, publishToGist, createNewFile, setFocusElement, createNewFolder, deletePath, renamePath, copyFile, copyFolder, runScript, emitContextMenuEvent, handleClickFile, handleExpandPath, addInputField, createWorkspace, fetchWorkspaceDirectory, renameWorkspace, switchToWorkspace, uploadFile, handleDownloadFiles, restoreBackupZip, moveFile, cloneRepository } from '../actions' import { initWorkspace, fetchDirectory, removeInputField, deleteWorkspace, clearPopUp, publishToGist, createNewFile, setFocusElement, createNewFolder,
deletePath, renamePath, copyFile, copyFolder, runScript, emitContextMenuEvent, handleClickFile, handleExpandPath, addInputField, createWorkspace,
fetchWorkspaceDirectory, renameWorkspace, switchToWorkspace, uploadFile, handleDownloadFiles, restoreBackupZip, cloneRepository, moveFile } from '../actions'
import { Modal, WorkspaceProps, WorkspaceTemplate } from '../types' import { Modal, WorkspaceProps, WorkspaceTemplate } from '../types'
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
import { Workspace } from '../remix-ui-workspace' import { Workspace } from '../remix-ui-workspace'
@ -126,11 +128,9 @@ export const FileSystemProvider = (props: WorkspaceProps) => {
const dispatchCloneRepository = async (url: string) => { const dispatchCloneRepository = async (url: string) => {
await cloneRepository(url) await cloneRepository(url)
} }
const dispatchMoveFile = async (src: string, dest: string) => { const dispatchMoveFile = async (src: string, dest: string) => {
await moveFile(src, dest) await moveFile(src, dest)
} }
useEffect(() => { useEffect(() => {
dispatchInitWorkspace() dispatchInitWorkspace()
}, []) }, [])
@ -247,3 +247,4 @@ export const FileSystemProvider = (props: WorkspaceProps) => {
} }
export default FileSystemProvider export default FileSystemProvider

@ -99,7 +99,6 @@ export interface FileExplorerProps {
dispatchAddInputField:(path: string, type: 'file' | 'folder') => Promise<void>, dispatchAddInputField:(path: string, type: 'file' | 'folder') => Promise<void>,
dispatchHandleExpandPath: (paths: string[]) => Promise<void> dispatchHandleExpandPath: (paths: string[]) => Promise<void>
dispatchMoveFile: (src: string, dest: string) => Promise<void>, dispatchMoveFile: (src: string, dest: string) => Promise<void>,
} }
export interface FileExplorerMenuProps { export interface FileExplorerMenuProps {

@ -10,8 +10,14 @@
"importHelpers": true, "importHelpers": true,
"target": "es2015", "target": "es2015",
"module": "commonjs", "module": "commonjs",
"typeRoots": ["node_modules/@types"], "typeRoots": [
"lib": ["es2017", "es2019", "dom"], "node_modules/@types"
],
"lib": [
"es2017",
"es2019",
"dom"
],
"skipLibCheck": true, "skipLibCheck": true,
"skipDefaultLibCheck": true, "skipDefaultLibCheck": true,
"baseUrl": ".", "baseUrl": ".",
@ -22,62 +28,120 @@
"@remix-project/remix-astwalker": [ "@remix-project/remix-astwalker": [
"dist/libs/remix-astwalker/src/index.js" "dist/libs/remix-astwalker/src/index.js"
], ],
"@remix-project/remix-debug": ["dist/libs/remix-debug/src/index.js"], "@remix-project/remix-debug": [
"@remix-project/remix-lib": ["dist/libs/remix-lib/src/index.js"], "dist/libs/remix-debug/src/index.js"
],
"@remix-project/remix-lib": [
"dist/libs/remix-lib/src/index.js"
],
"@remix-project/remix-simulator": [ "@remix-project/remix-simulator": [
"dist/libs/remix-simulator/src/index.js" "dist/libs/remix-simulator/src/index.js"
], ],
"@remix-project/remix-solidity": [ "@remix-project/remix-solidity": [
"dist/libs/remix-solidity/src/index.js" "dist/libs/remix-solidity/src/index.js"
], ],
"@remix-project/remix-tests": ["dist/libs/remix-tests/src/index.js"], "@remix-project/remix-tests": [
"dist/libs/remix-tests/src/index.js"
],
"@remix-project/remix-url-resolver": [ "@remix-project/remix-url-resolver": [
"dist/libs/remix-url-resolver/src/index.js" "dist/libs/remix-url-resolver/src/index.js"
], ],
"@remix-project/remix-ws-templates": [ "@remix-project/remix-ws-templates": [
"dist/libs/remix-ws-templates/src/index.js" "dist/libs/remix-ws-templates/src/index.js"
], ],
"@remixproject/debugger-plugin": ["apps/debugger/src/index.ts"], "@remixproject/debugger-plugin": [
"apps/debugger/src/index.ts"
],
"@remixproject/solidity-compiler-plugin": [ "@remixproject/solidity-compiler-plugin": [
"apps/solidity-compiler/src/index.ts" "apps/solidity-compiler/src/index.ts"
], ],
"@remix-project/remixd": ["dist/libs/remixd/index.js"], "@remix-project/remixd": [
"@remix-ui/tree-view": ["libs/remix-ui/tree-view/src/index.ts"], "dist/libs/remixd/index.js"
"@remix-ui/search": ["libs/remix-ui/search/src/index.ts"], ],
"@remix-ui/debugger-ui": ["libs/remix-ui/debugger-ui/src/index.ts"], "@remix-ui/tree-view": [
"@remix-ui/utils": ["libs/remix-ui/utils/src/index.ts"], "libs/remix-ui/tree-view/src/index.ts"
"@remix-ui/clipboard": ["libs/remix-ui/clipboard/src/index.ts"], ],
"@remix-project/remix-solidity-ts": ["libs/remix-solidity/src/index.ts"], "@remix-ui/search": [
"@remix-project/remix-lib-ts": ["libs/remix-lib/src/index.ts"], "libs/remix-ui/search/src/index.ts"
"@remix-ui/modal-dialog": ["libs/remix-ui/modal-dialog/src/index.ts"], ],
"@remix-ui/toaster": ["libs/remix-ui/toaster/src/index.ts"], "@remix-ui/debugger-ui": [
"@remix-ui/file-explorer": ["libs/remix-ui/file-explorer/src/index.ts"], "libs/remix-ui/debugger-ui/src/index.ts"
"@remix-ui/workspace": ["libs/remix-ui/workspace/src/index.ts"], ],
"@remix-ui/utils": [
"libs/remix-ui/utils/src/index.ts"
],
"@remix-ui/clipboard": [
"libs/remix-ui/clipboard/src/index.ts"
],
"@remix-project/remix-solidity-ts": [
"libs/remix-solidity/src/index.ts"
],
"@remix-project/remix-lib-ts": [
"libs/remix-lib/src/index.ts"
],
"@remix-ui/modal-dialog": [
"libs/remix-ui/modal-dialog/src/index.ts"
],
"@remix-ui/toaster": [
"libs/remix-ui/toaster/src/index.ts"
],
"@remix-ui/file-explorer": [
"libs/remix-ui/file-explorer/src/index.ts"
],
"@remix-ui/workspace": [
"libs/remix-ui/workspace/src/index.ts"
],
"@remix-ui/static-analyser": [ "@remix-ui/static-analyser": [
"libs/remix-ui/static-analyser/src/index.ts" "libs/remix-ui/static-analyser/src/index.ts"
], ],
"@remix-ui/checkbox": ["libs/remix-ui/checkbox/src/index.ts"], "@remix-ui/checkbox": [
"@remix-ui/settings": ["libs/remix-ui/settings/src/index.ts"], "libs/remix-ui/checkbox/src/index.ts"
"@remix-project/core-plugin": ["libs/remix-core-plugin/src/index.ts"], ],
"@remix-ui/settings": [
"libs/remix-ui/settings/src/index.ts"
],
"@remix-project/core-plugin": [
"libs/remix-core-plugin/src/index.ts"
],
"@remix-ui/solidity-compiler": [ "@remix-ui/solidity-compiler": [
"libs/remix-ui/solidity-compiler/src/index.ts" "libs/remix-ui/solidity-compiler/src/index.ts"
], ],
"@remix-ui/publish-to-storage": [ "@remix-ui/publish-to-storage": [
"libs/remix-ui/publish-to-storage/src/index.ts" "libs/remix-ui/publish-to-storage/src/index.ts"
], ],
"@remix-ui/renderer": ["libs/remix-ui/renderer/src/index.ts"], "@remix-ui/renderer": [
"@remix-ui/terminal": ["libs/remix-ui/terminal/src/index.ts"], "libs/remix-ui/renderer/src/index.ts"
"@remix-ui/plugin-manager": ["libs/remix-ui/plugin-manager/src/index.ts"], ],
"@remix-ui/home-tab": ["libs/remix-ui/home-tab/src/index.ts"], "@remix-ui/terminal": [
"@remix-ui/editor": ["libs/remix-ui/editor/src/index.ts"], "libs/remix-ui/terminal/src/index.ts"
"@remix-ui/tabs": ["libs/remix-ui/tabs/src/index.ts"], ],
"@remix-ui/helper": ["libs/remix-ui/helper/src/index.ts"], "@remix-ui/plugin-manager": [
"@remix-ui/app": ["libs/remix-ui/app/src/index.ts"], "libs/remix-ui/plugin-manager/src/index.ts"
],
"@remix-ui/home-tab": [
"libs/remix-ui/home-tab/src/index.ts"
],
"@remix-ui/editor": [
"libs/remix-ui/editor/src/index.ts"
],
"@remix-ui/tabs": [
"libs/remix-ui/tabs/src/index.ts"
],
"@remix-ui/helper": [
"libs/remix-ui/helper/src/index.ts"
],
"@remix-ui/app": [
"libs/remix-ui/app/src/index.ts"
],
"@remix-ui/vertical-icons-panel": [ "@remix-ui/vertical-icons-panel": [
"libs/remix-ui/vertical-icons-panel/src/index.ts" "libs/remix-ui/vertical-icons-panel/src/index.ts"
], ],
"@remix-ui/theme-module": ["libs/remix-ui/theme-module/src/index.ts"], "@remix-ui/theme-module": [
"@remix-ui/panel": ["libs/remix-ui/panel/src/index.ts"], "libs/remix-ui/theme-module/src/index.ts"
],
"@remix-ui/panel": [
"libs/remix-ui/panel/src/index.ts"
],
"@remix-ui/editor-context-view": [ "@remix-ui/editor-context-view": [
"libs/remix-ui/editor-context-view/src/index.ts" "libs/remix-ui/editor-context-view/src/index.ts"
], ],
@ -92,5 +156,8 @@
"@remix-ui/tooltip-popup": ["libs/remix-ui/tooltip-popup/src/index.ts"] "@remix-ui/tooltip-popup": ["libs/remix-ui/tooltip-popup/src/index.ts"]
} }
}, },
"exclude": ["node_modules", "tmp"] "exclude": [
"node_modules",
"tmp"
]
} }
Loading…
Cancel
Save