diff --git a/package-lock.json b/package-lock.json
index 0661b049..68a9121a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2694,6 +2694,42 @@
"@date-io/core": "^2.10.6"
}
},
+ "@dnd-kit/accessibility": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-1.0.2.tgz",
+ "integrity": "sha512-aQq+B4But+369cYYtmXPUhqf26Fy9b/nR+uAP4cbhf3TXMlCqorT7bO7dT7cNe+me2DOf61GVr0mkrWtfsvR3A==",
+ "requires": {
+ "tslib": "^2.0.0"
+ }
+ },
+ "@dnd-kit/core": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-1.0.2.tgz",
+ "integrity": "sha512-etf7LmAye+Y3TDiHAivGPr4TXyDVtyV7jMxPPAVErdPoxKUcVjibnRhDeJlA7cRhioQE+rKmvs/EZ0XijuqrbQ==",
+ "requires": {
+ "@dnd-kit/accessibility": "^1.0.2",
+ "@dnd-kit/utilities": "^1.0.2",
+ "tslib": "^2.0.0"
+ }
+ },
+ "@dnd-kit/sortable": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@dnd-kit/sortable/-/sortable-1.0.2.tgz",
+ "integrity": "sha512-lma9+LBATJ5A7hdnDqtD4Nam1dEX4fQYxi8W+C6qNk3nhG1AT1fjZ+GwokvDCEbGCD6GNDHlWZybJdc7dqb7mQ==",
+ "requires": {
+ "@dnd-kit/core": "^1.0.2",
+ "@dnd-kit/utilities": "^1.0.2",
+ "tslib": "^2.0.0"
+ }
+ },
+ "@dnd-kit/utilities": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-1.0.2.tgz",
+ "integrity": "sha512-RC3c9OVfr9Nx5acNwy278RCI0UOr8e08XQmws1w0lx+i+YIu74lQqat0MXR3zyQHimrduXRG/ctciuwj1JOgkQ==",
+ "requires": {
+ "tslib": "^2.0.0"
+ }
+ },
"@dsherret/to-absolute-glob": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@dsherret/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz",
@@ -4951,11 +4987,6 @@
"integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=",
"dev": true
},
- "array-move": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/array-move/-/array-move-3.0.1.tgz",
- "integrity": "sha512-H3Of6NIn2nNU1gsVDqDnYKY/LCdWvCMMOWifNGhKcVQgiZ6nOek39aESOvro6zmueP07exSl93YLvkN4fZOkSg=="
- },
"array-reduce": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz",
@@ -12433,15 +12464,6 @@
"p-is-promise": "^1.1.0"
}
},
- "invariant": {
- "version": "2.2.4",
- "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
- "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
- "dev": true,
- "requires": {
- "loose-envify": "^1.0.0"
- }
- },
"inversify": {
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/inversify/-/inversify-5.0.5.tgz",
@@ -16148,17 +16170,6 @@
"react-is": "^16.13.1"
}
},
- "react-sortable-hoc": {
- "version": "1.11.0",
- "resolved": "https://registry.npmjs.org/react-sortable-hoc/-/react-sortable-hoc-1.11.0.tgz",
- "integrity": "sha512-v1CDCvdfoR3zLGNp6qsBa4J1BWMEVH25+UKxF/RvQRh+mrB+emqtVHMgZ+WreUiKJoEaiwYoScaueIKhMVBHUg==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.2.0",
- "invariant": "^2.2.4",
- "prop-types": "^15.5.7"
- }
- },
"react-transition-group": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz",
@@ -18751,8 +18762,7 @@
"tslib": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
- "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==",
- "dev": true
+ "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
},
"tsutils": {
"version": "3.21.0",
diff --git a/package.json b/package.json
index 56203c99..b1ac2895 100755
--- a/package.json
+++ b/package.json
@@ -68,10 +68,12 @@
}
},
"dependencies": {
+ "@dnd-kit/core": "^1.0.2",
+ "@dnd-kit/sortable": "^1.0.2",
+ "@dnd-kit/utilities": "^1.0.2",
"@material-ui/styled-engine-sc": "^5.0.0-alpha.25",
"@rematch/core": "^2.0.0",
"@tiddlygit/tiddlywiki": "5.1.24-prerelease.20210103",
- "array-move": "^3.0.1",
"beautiful-react-hooks": "^0.31.0",
"bluebird": "^3.7.2",
"chokidar": "^3.5.1",
@@ -187,7 +189,6 @@
"react-dom": "17.0.1",
"react-i18next": "^11.8.6",
"react-redux": "7.2.2",
- "react-sortable-hoc": "1.11.0",
"redux": "4.0.5",
"rimraf": "^3.0.2",
"simplebar": "6.0.0-beta.4",
diff --git a/src/pages/Main/SortableWorkspaceSelector.tsx b/src/pages/Main/SortableWorkspaceSelector.tsx
index bf5fd6ae..8166187a 100644
--- a/src/pages/Main/SortableWorkspaceSelector.tsx
+++ b/src/pages/Main/SortableWorkspaceSelector.tsx
@@ -1,72 +1,76 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
-import { SortableContainer as sortableContainer, SortableElement as sortableElement } from 'react-sortable-hoc';
+import { useSortable } from '@dnd-kit/sortable';
+import { CSS } from '@dnd-kit/utilities';
import { WindowNames } from '@services/windows/WindowProperties';
import WorkspaceSelector from './WorkspaceSelector';
import { IWorkspace } from '@services/workspaces/interface';
import defaultIcon from '../../images/default-icon.png';
-export const SortableContainer = sortableContainer(({ children }: { children: React.ReactNode }) =>
{children}
);
-
export interface ISortableItemProps {
index: number;
workspace: IWorkspace;
}
-function SortableWorkspaceSelector({ index, workspace }: ISortableItemProps) {
+export function SortableWorkspaceSelector({ index, workspace }: ISortableItemProps) {
const { t } = useTranslation();
const { active, id, name, picturePath, hibernated, transparentBackground, isSubWiki, tagName } = workspace;
+ const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id });
+ const style = {
+ transform: CSS.Transform.toString(transform),
+ transition,
+ };
return (
- {
- if (isSubWiki) {
- await window.service.wiki.requestOpenTiddlerInWiki(tagName);
- } else {
- const activeWorkspace = await window.service.workspace.getActiveWorkspace();
- if (activeWorkspace?.id === id) {
- await window.service.wiki.requestWikiSendActionMessage('tm-home');
+
+ {
+ if (isSubWiki) {
+ await window.service.wiki.requestOpenTiddlerInWiki(tagName);
} else {
- await window.service.workspaceView.setActiveWorkspaceView(id);
+ const activeWorkspace = await window.service.workspace.getActiveWorkspace();
+ if (activeWorkspace?.id === id) {
+ await window.service.wiki.requestWikiSendActionMessage('tm-home');
+ } else {
+ await window.service.workspaceView.setActiveWorkspaceView(id);
+ }
}
- }
- }}
- onContextMenu={() => {
- const template = [
- {
- label: t('WorkspaceSelector.EditWorkspace'),
- click: async () => await window.service.window.open(WindowNames.editWorkspace, { workspaceID: id }),
- },
- {
- label: t('WorkspaceSelector.RemoveWorkspace'),
- click: async () => await window.service.workspaceView.removeWorkspaceView(id),
- },
- ];
-
- if (!active && !isSubWiki) {
- template.splice(1, 0, {
- label: hibernated ? 'Wake Up Workspace' : 'Hibernate Workspace',
- click: async () => {
- if (hibernated) {
- return await window.service.workspaceView.wakeUpWorkspaceView(id);
- }
- return await window.service.workspaceView.hibernateWorkspaceView(id);
+ }}
+ onContextMenu={() => {
+ const template = [
+ {
+ label: t('WorkspaceSelector.EditWorkspace'),
+ click: async () => await window.service.window.open(WindowNames.editWorkspace, { workspaceID: id }),
},
- });
- }
+ {
+ label: t('WorkspaceSelector.RemoveWorkspace'),
+ click: async () => await window.service.workspaceView.removeWorkspaceView(id),
+ },
+ ];
- void window.service.menu.buildContextMenuAndPopup(template);
- }}
- />
+ if (!active && !isSubWiki) {
+ template.splice(1, 0, {
+ label: hibernated ? 'Wake Up Workspace' : 'Hibernate Workspace',
+ click: async () => {
+ if (hibernated) {
+ return await window.service.workspaceView.wakeUpWorkspaceView(id);
+ }
+ return await window.service.workspaceView.hibernateWorkspaceView(id);
+ },
+ });
+ }
+
+ void window.service.menu.buildContextMenuAndPopup(template);
+ }}
+ />
+
);
}
-
-export default sortableElement(SortableWorkspaceSelector);
diff --git a/src/pages/Main/WorkspaceSelector.tsx b/src/pages/Main/WorkspaceSelector.tsx
index 60c94818..38abd491 100644
--- a/src/pages/Main/WorkspaceSelector.tsx
+++ b/src/pages/Main/WorkspaceSelector.tsx
@@ -1,11 +1,13 @@
+import Promise from 'bluebird';
import React, { useState, useEffect } from 'react';
-import classNames from 'classnames';
import { useTranslation } from 'react-i18next';
import BadgeRaw from '@material-ui/core/Badge';
import styled, { css } from 'styled-components';
import defaultIcon from '../../images/default-icon.png';
+Promise.config({ cancellation: true });
+
// TODO: &:hover { background: theme.palette.action.hover;
const Root = styled.div<{ hibernated?: boolean; active?: boolean }>`
height: fit-content;
@@ -125,10 +127,14 @@ export default function WorkspaceSelector({
const { t } = useTranslation();
const [shortWorkspaceName, shortWorkspaceNameSetter] = useState(t('Loading'));
useEffect(() => {
- void (async () => {
- const baseName = await window.service.context.getBaseName(workspaceName);
+ const setBaseNamePromise = new Promise((resolve) => {
+ window.service.context.getBaseName(workspaceName).then((baseName) => resolve(baseName));
+ });
+
+ setBaseNamePromise.then((baseName) => {
shortWorkspaceNameSetter(baseName !== undefined ? baseName : t('WorkspaceSelector.BadWorkspacePath'));
- })();
+ });
+ return () => setBaseNamePromise.cancel();
}, [workspaceName]);
return (
diff --git a/src/pages/Main/index.tsx b/src/pages/Main/index.tsx
index 699f207f..b63cb144 100644
--- a/src/pages/Main/index.tsx
+++ b/src/pages/Main/index.tsx
@@ -1,7 +1,8 @@
import React from 'react';
-import arrayMove from 'array-move';
import styled, { css } from 'styled-components';
import { AsyncReturnType } from 'type-fest';
+import { DndContext } from '@dnd-kit/core';
+import { SortableContext, arrayMove, verticalListSortingStrategy } from '@dnd-kit/sortable';
import SimpleBar from 'simplebar-react';
import 'simplebar/dist/simplebar.min.css';
@@ -24,7 +25,7 @@ import DraggableRegion from './DraggableRegion';
import arrowWhite from '@/images/arrow-white.png';
import arrowBlack from '@/images/arrow-black.png';
-import SortableWorkspaceSelector, { SortableContainer } from './SortableWorkspaceSelector';
+import { SortableWorkspaceSelector } from './SortableWorkspaceSelector';
import { IWorkspace } from '@services/workspaces/interface';
import { IPreferences } from '@services/preferences/interface';
@@ -180,6 +181,7 @@ export default function Main(): JSX.Element {
}, {} as AsyncReturnType);
const requestReload = async (): Promise => await window.service.window.reload(window.meta.windowName);
+ const workspaceIDs = workspacesList.map((workspace) => workspace.id);
return (
{workspacesList.length > 0 && }
@@ -187,10 +189,11 @@ export default function Main(): JSX.Element {
{sidebar === true && (
- {
- if (oldIndex === newIndex) return;
+ {
+ if (over === null || active.id === over.id) return;
+ const oldIndex = workspaceIDs.indexOf(active.id);
+ const newIndex = workspaceIDs.indexOf(over.id);
const newWorkspacesList = arrayMove(workspacesList, oldIndex, newIndex);
const newWorkspaces: Record = {};
@@ -201,10 +204,12 @@ export default function Main(): JSX.Element {
await window.service.workspace.setWorkspaces(newWorkspaces);
}}>
- {workspacesList.map((workspace, index) => (
-
- ))}
-
+
+ {workspacesList.map((workspace, index) => (
+
+ ))}
+
+
await window.service.window.open(WindowNames.addWorkspace)} />