diff --git a/.yarn/cache/@react-dnd-asap-npm-5.0.2-66021d3d61-18f040e535.zip b/.yarn/cache/@react-dnd-asap-npm-5.0.2-66021d3d61-18f040e535.zip deleted file mode 100644 index 62c4eb592..000000000 Binary files a/.yarn/cache/@react-dnd-asap-npm-5.0.2-66021d3d61-18f040e535.zip and /dev/null differ diff --git a/.yarn/cache/@react-dnd-invariant-npm-4.0.2-826eacc1ea-594f6d7889.zip b/.yarn/cache/@react-dnd-invariant-npm-4.0.2-826eacc1ea-594f6d7889.zip deleted file mode 100644 index d26aa718e..000000000 Binary files a/.yarn/cache/@react-dnd-invariant-npm-4.0.2-826eacc1ea-594f6d7889.zip and /dev/null differ diff --git a/.yarn/cache/@react-dnd-shallowequal-npm-4.0.2-f944714335-7f21d691bd.zip b/.yarn/cache/@react-dnd-shallowequal-npm-4.0.2-f944714335-7f21d691bd.zip deleted file mode 100644 index e58d35bdf..000000000 Binary files a/.yarn/cache/@react-dnd-shallowequal-npm-4.0.2-f944714335-7f21d691bd.zip and /dev/null differ diff --git a/.yarn/cache/dnd-core-npm-16.0.1-552224cee0-b7d3ef4664.zip b/.yarn/cache/dnd-core-npm-16.0.1-552224cee0-b7d3ef4664.zip deleted file mode 100644 index d4a0da59a..000000000 Binary files a/.yarn/cache/dnd-core-npm-16.0.1-552224cee0-b7d3ef4664.zip and /dev/null differ diff --git a/.yarn/cache/react-dnd-html5-backend-npm-16.0.1-754940d855-e2368bf85d.zip b/.yarn/cache/react-dnd-html5-backend-npm-16.0.1-754940d855-e2368bf85d.zip deleted file mode 100644 index 5639443b3..000000000 Binary files a/.yarn/cache/react-dnd-html5-backend-npm-16.0.1-754940d855-e2368bf85d.zip and /dev/null differ diff --git a/.yarn/cache/react-dnd-npm-16.0.1-974f047d7b-e8da2186aa.zip b/.yarn/cache/react-dnd-npm-16.0.1-974f047d7b-e8da2186aa.zip deleted file mode 100644 index f0692fcfa..000000000 Binary files a/.yarn/cache/react-dnd-npm-16.0.1-974f047d7b-e8da2186aa.zip and /dev/null differ diff --git a/.yarn/cache/react-dnd-touch-backend-npm-16.0.1-2b96ba84be-5362c5f426.zip b/.yarn/cache/react-dnd-touch-backend-npm-16.0.1-2b96ba84be-5362c5f426.zip deleted file mode 100644 index 850459def..000000000 Binary files a/.yarn/cache/react-dnd-touch-backend-npm-16.0.1-2b96ba84be-5362c5f426.zip and /dev/null differ diff --git a/.yarn/cache/redux-npm-4.2.0-4688cc8d65-75f3955c89.zip b/.yarn/cache/redux-npm-4.2.0-4688cc8d65-75f3955c89.zip deleted file mode 100644 index 6ecf8c2c9..000000000 Binary files a/.yarn/cache/redux-npm-4.2.0-4688cc8d65-75f3955c89.zip and /dev/null differ diff --git a/packages/blocks-editor/src/Editor/BlocksEditor.tsx b/packages/blocks-editor/src/Editor/BlocksEditor.tsx index 3360bbe12..994b4113d 100644 --- a/packages/blocks-editor/src/Editor/BlocksEditor.tsx +++ b/packages/blocks-editor/src/Editor/BlocksEditor.tsx @@ -31,8 +31,6 @@ import FloatingLinkEditorPlugin from '../Lexical/Plugins/FloatingLinkEditorPlugi import {truncateString} from './Utils'; import {SuperEditorContentId} from './Constants'; -const BlockDragEnabled = false; - type BlocksEditorProps = { onChange: (value: string, preview: string) => void; className?: string; @@ -130,11 +128,9 @@ export const BlocksEditor: FunctionComponent = ({ <> + )} - {floatingAnchorElem && BlockDragEnabled && ( - <>{} - )} ); }; diff --git a/packages/blocks-editor/src/Lexical/Plugins/DraggableBlockPlugin/index.scss b/packages/blocks-editor/src/Lexical/Plugins/DraggableBlockPlugin/index.scss index 34db2db8b..0b4bd4d57 100644 --- a/packages/blocks-editor/src/Lexical/Plugins/DraggableBlockPlugin/index.scss +++ b/packages/blocks-editor/src/Lexical/Plugins/DraggableBlockPlugin/index.scss @@ -10,10 +10,9 @@ } .draggable-block-menu .icon { - width: 16px; - height: 16px; - opacity: 0.3; - background-image: url(#{$blocks-editor-icons-path}/draggable-block-menu.svg); + width: 1rem; + height: 1rem; + opacity: 0.4; } .draggable-block-menu:active { @@ -21,13 +20,14 @@ } .draggable-block-menu:hover { - background-color: #efefef; + background-color: var(--sn-stylekit-contrast-background-color); + padding: 3px; } .draggable-block-target-line { pointer-events: none; - background: deepskyblue; - height: 4px; + background: var(--sn-stylekit-info-color); + height: 0.25rem; position: absolute; left: 0; top: 0; diff --git a/packages/blocks-editor/src/Lexical/Plugins/DraggableBlockPlugin/index.tsx b/packages/blocks-editor/src/Lexical/Plugins/DraggableBlockPlugin/index.tsx index c52985f3a..4ba980e1c 100644 --- a/packages/blocks-editor/src/Lexical/Plugins/DraggableBlockPlugin/index.tsx +++ b/packages/blocks-editor/src/Lexical/Plugins/DraggableBlockPlugin/index.tsx @@ -19,16 +19,18 @@ import { } from 'lexical'; import {DragEvent as ReactDragEvent, useEffect, useRef, useState} from 'react'; import {createPortal} from 'react-dom'; +import {LexicalDraggableBlockMenu} from '@standardnotes/icons'; import {isHTMLElement} from '../../Utils/guard'; import {Point} from '../../Utils/point'; import {Rect} from '../../Utils/rect'; -const SPACE = 4; +const SPACE = -16; const TARGET_LINE_HALF_HEIGHT = 2; const DRAGGABLE_BLOCK_MENU_CLASSNAME = 'draggable-block-menu'; const DRAG_DATA_FORMAT = 'application/x-lexical-drag-block'; const TEXT_BOX_HORIZONTAL_PADDING = 28; +const TARGET_LINE_SPACE_FROM_LEFT = 0; const Downward = 1; const Upward = -1; @@ -179,7 +181,7 @@ function setTargetLine( } const top = lineTop - anchorTop - TARGET_LINE_HALF_HEIGHT; - const left = TEXT_BOX_HORIZONTAL_PADDING - SPACE; + const left = TARGET_LINE_SPACE_FROM_LEFT; targetLineElem.style.transform = `translate(${left}px, ${top}px)`; targetLineElem.style.width = `${ @@ -347,7 +349,9 @@ function useDraggableBlockMenu( draggable={true} onDragStart={onDragStart} onDragEnd={onDragEnd}> -
+
+ +
, diff --git a/packages/icons/src/Lexical/index.ts b/packages/icons/src/Lexical/index.ts index fa97e538c..e4f3b807e 100644 --- a/packages/icons/src/Lexical/index.ts +++ b/packages/icons/src/Lexical/index.ts @@ -27,6 +27,7 @@ import TypeSubscript from './type-subscript.svg' import TypeSuperscript from './type-superscript.svg' import TypeUnderline from './type-underline.svg' import LexicalPencilFill from './pencil-fill.svg' +import LexicalDraggableBlockMenu from './draggable-block-menu.svg' export { LexicalCaretRightFill, @@ -58,4 +59,5 @@ export { TypeSuperscript, TypeUnderline, LexicalPencilFill, + LexicalDraggableBlockMenu, } diff --git a/packages/web/package.json b/packages/web/package.json index 5caac7a72..5f01185ad 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -99,9 +99,6 @@ "prettier-plugin-tailwindcss": "^0.1.13", "qrcode.react": "^3.1.0", "react": "^18.2.0", - "react-dnd": "^16.0.1", - "react-dnd-html5-backend": "^16.0.1", - "react-dnd-touch-backend": "^16.0.1", "react-dom": "^18.2.0", "react-refresh": "^0.14.0", "sass-loader": "*", diff --git a/packages/web/src/javascripts/Components/Tags/DragNDrop.ts b/packages/web/src/javascripts/Components/Tags/DragNDrop.ts index 575f018ee..6ecfb1dc9 100644 --- a/packages/web/src/javascripts/Components/Tags/DragNDrop.ts +++ b/packages/web/src/javascripts/Components/Tags/DragNDrop.ts @@ -1,9 +1 @@ -export enum ItemTypes { - TAG = 'TAG', -} - -export type DropItemTag = { uuid: string } - -export type DropItem = DropItemTag - -export type DropProps = { isOver: boolean; canDrop: boolean } +export const TagDragDataFormat = 'application/x-sn-drag-tag' diff --git a/packages/web/src/javascripts/Components/Tags/RootTagDropZone.tsx b/packages/web/src/javascripts/Components/Tags/RootTagDropZone.tsx index 0e9f39ebc..ac1438fd4 100644 --- a/packages/web/src/javascripts/Components/Tags/RootTagDropZone.tsx +++ b/packages/web/src/javascripts/Components/Tags/RootTagDropZone.tsx @@ -1,39 +1,50 @@ import Icon from '@/Components/Icon/Icon' -import { usePremiumModal } from '@/Hooks/usePremiumModal' -import { FeaturesController } from '@/Controllers/FeaturesController' import { NavigationController } from '@/Controllers/Navigation/NavigationController' +import { classNames } from '@/Utils/ConcatenateClassNames' import { observer } from 'mobx-react-lite' -import { FunctionComponent } from 'react' -import { useDrop } from 'react-dnd' -import { DropItem, DropProps, ItemTypes } from './DragNDrop' +import { DragEventHandler, FunctionComponent, useCallback, useState } from 'react' +import { TagDragDataFormat } from './DragNDrop' type Props = { tagsState: NavigationController - featuresState: FeaturesController } const RootTagDropZone: FunctionComponent = ({ tagsState }) => { - const premiumModal = usePremiumModal() + const [isOver, setIsOver] = useState(false) - const [{ isOver, canDrop }, dropRef] = useDrop( - () => ({ - accept: ItemTypes.TAG, - canDrop: (item) => { - return tagsState.hasParent(item.uuid) - }, - drop: (item) => { - tagsState.assignParent(item.uuid, undefined).catch(console.error) - }, - collect: (monitor) => ({ - isOver: !!monitor.isOver(), - canDrop: !!monitor.canDrop(), - }), - }), - [tagsState, premiumModal], + const removeDragIndicator = useCallback(() => { + setIsOver(false) + }, []) + + const onDragOver: DragEventHandler = useCallback((event): void => { + if (event.dataTransfer.types.includes(TagDragDataFormat)) { + event.preventDefault() + setIsOver(true) + } + }, []) + + const onDrop: DragEventHandler = useCallback( + (event): void => { + setIsOver(false) + const draggedTagUuid = event.dataTransfer.getData(TagDragDataFormat) + if (!draggedTagUuid) { + return + } + if (draggedTagUuid) { + void tagsState.assignParent(draggedTagUuid, undefined) + } + }, + [tagsState], ) return ( -
+

Move the tag here to
diff --git a/packages/web/src/javascripts/Components/Tags/TagsList.tsx b/packages/web/src/javascripts/Components/Tags/TagsList.tsx index beb75fccc..983c8a733 100644 --- a/packages/web/src/javascripts/Components/Tags/TagsList.tsx +++ b/packages/web/src/javascripts/Components/Tags/TagsList.tsx @@ -2,8 +2,6 @@ import { ViewControllerManager } from '@/Controllers/ViewControllerManager' import { SNTag } from '@standardnotes/snjs' import { observer } from 'mobx-react-lite' import { FunctionComponent, useCallback } from 'react' -import { DndProvider } from 'react-dnd' -import { HTML5Backend } from 'react-dnd-html5-backend' import RootTagDropZone from './RootTagDropZone' import { TagListSectionType } from './TagListSection' import { TagsListItem } from './TagsListItem' @@ -17,8 +15,6 @@ const TagsList: FunctionComponent = ({ viewControllerManager, type }: Pro const navigationController = viewControllerManager.navigationController const allTags = type === 'all' ? navigationController.allLocalRootTags : navigationController.starredTags - const backend = HTML5Backend - const openTagContextMenu = useCallback( (posX: number, posY: number) => { viewControllerManager.navigationController.setContextMenuClickLocation({ @@ -40,7 +36,7 @@ const TagsList: FunctionComponent = ({ viewControllerManager, type }: Pro ) return ( - + <> {allTags.length === 0 ? (

No tags or folders. Create one using the add button above. @@ -61,15 +57,10 @@ const TagsList: FunctionComponent = ({ viewControllerManager, type }: Pro /> ) })} - {type === 'all' && ( - - )} + {type === 'all' && } )} - + ) } diff --git a/packages/web/src/javascripts/Components/Tags/TagsListItem.tsx b/packages/web/src/javascripts/Components/Tags/TagsListItem.tsx index e85836d2d..6b9064820 100644 --- a/packages/web/src/javascripts/Components/Tags/TagsListItem.tsx +++ b/packages/web/src/javascripts/Components/Tags/TagsListItem.tsx @@ -1,6 +1,5 @@ import Icon from '@/Components/Icon/Icon' import { FOCUSABLE_BUT_NOT_TABBABLE, TAG_FOLDERS_FEATURE_NAME } from '@/Constants/Constants' -import { usePremiumModal } from '@/Hooks/usePremiumModal' import { KeyboardKey } from '@standardnotes/ui-services' import { FeaturesController } from '@/Controllers/FeaturesController' import { NavigationController } from '@/Controllers/Navigation/NavigationController' @@ -9,6 +8,7 @@ import { IconType, SNTag } from '@standardnotes/snjs' import { computed } from 'mobx' import { observer } from 'mobx-react-lite' import { + DragEventHandler, FormEventHandler, FunctionComponent, KeyboardEventHandler, @@ -19,16 +19,15 @@ import { useRef, useState, } from 'react' -import { useDrag, useDrop } from 'react-dnd' -import { DropItem, DropProps, ItemTypes } from './DragNDrop' import { useResponsiveAppPane } from '../ResponsivePane/ResponsivePaneProvider' import { AppPaneId } from '../ResponsivePane/AppPaneMetadata' import { classNames } from '@/Utils/ConcatenateClassNames' -import { mergeRefs } from '@/Hooks/mergeRefs' import { useFileDragNDrop } from '../FileDragNDropProvider/FileDragNDropProvider' import { LinkingController } from '@/Controllers/LinkingController' import { TagListSectionType } from './TagListSection' import { log, LoggingDomain } from '@/Logging' +import { TagDragDataFormat } from './DragNDrop' +import { usePremiumModal } from '@/Hooks/usePremiumModal' type Props = { tag: SNTag @@ -68,6 +67,8 @@ export const TagsListItem: FunctionComponent = observer( const [showChildren, setShowChildren] = useState(tag.expanded) const [hadChildren, setHadChildren] = useState(hasChildren) + const [isBeingDraggedOver, setIsBeingDraggedOver] = useState(false) + useEffect(() => { if (!hadChildren && hasChildren) { setShowChildren(true) @@ -151,43 +152,6 @@ export const TagsListItem: FunctionComponent = observer( } }, [subtagInputRef, isAddingSubtag]) - const [, dragRef] = useDrag( - () => ({ - type: ItemTypes.TAG, - item: { uuid: tag.uuid }, - canDrag: () => { - return true - }, - collect: (monitor) => ({ - isDragging: !!monitor.isDragging(), - }), - }), - [tag], - ) - - const [{ isOver, canDrop }, dropRef] = useDrop( - () => ({ - accept: ItemTypes.TAG, - canDrop: (item) => { - return navigationController.isValidTagParent(tag, item as SNTag) - }, - drop: (item) => { - if (!hasFolders) { - premiumModal.activate(TAG_FOLDERS_FEATURE_NAME) - return - } - navigationController.assignParent(item.uuid, tag.uuid).catch(console.error) - }, - collect: (monitor) => ({ - isOver: !!monitor.isOver(), - canDrop: !!monitor.canDrop(), - }), - }), - [tag, navigationController, hasFolders, premiumModal], - ) - - const readyToDrop = isOver && canDrop - const toggleContextMenu: MouseEventHandler = useCallback( (event) => { event.preventDefault() @@ -236,14 +200,59 @@ export const TagsListItem: FunctionComponent = observer( log(LoggingDomain.NavigationList, 'Rendering TagsListItem') + const onDragStart: DragEventHandler = useCallback( + (event) => { + event.dataTransfer.setData(TagDragDataFormat, tag.uuid) + }, + [tag.uuid], + ) + + const onDragEnter: DragEventHandler = useCallback((event): void => { + if (event.dataTransfer.types.includes(TagDragDataFormat)) { + event.preventDefault() + setIsBeingDraggedOver(true) + } + }, []) + + const removeDragIndicator = useCallback(() => { + setIsBeingDraggedOver(false) + }, []) + + const onDragOver: DragEventHandler = useCallback((event): void => { + if (event.dataTransfer.types.includes(TagDragDataFormat)) { + event.preventDefault() + } + }, []) + + const onDrop: DragEventHandler = useCallback( + (event): void => { + setIsBeingDraggedOver(false) + const draggedTagUuid = event.dataTransfer.getData(TagDragDataFormat) + if (!draggedTagUuid) { + return + } + if (!navigationController.isValidTagParent(tag, { uuid: draggedTagUuid } as SNTag)) { + return + } + if (!hasFolders) { + premiumModal.activate(TAG_FOLDERS_FEATURE_NAME) + return + } + if (draggedTagUuid) { + void navigationController.assignParent(draggedTagUuid, tag.uuid) + } + }, + [hasFolders, navigationController, premiumModal, tag], + ) + return ( <>
= observer( e.preventDefault() onContextMenu(tag, e.clientX, e.clientY) }} + draggable={true} + onDragStart={onDragStart} + onDragEnter={onDragEnter} + onDragExit={removeDragIndicator} + onDragOver={onDragOver} + onDragLeave={removeDragIndicator} + onDrop={onDrop} > -
-
+
+
= 3.3.1" - "@types/node": ">= 12" - "@types/react": ">= 16" - react: ">= 16.14" - peerDependenciesMeta: - "@types/hoist-non-react-statics": - optional: true - "@types/node": - optional: true - "@types/react": - optional: true - checksum: e8da2186aaafcd5bb41c090a995c963a7c3c73c20991667a2cfc0c800d7f7f73913414b2e61c437cdb6221bb2151bd5174088b8b42c17056a896fc4d1da5729f - languageName: node - linkType: hard - "react-dom@link:../web/node_modules/react-dom::locator=%40standardnotes%2Ftoast%40workspace%3Apackages%2Ftoast": version: 0.0.0-use.local resolution: "react-dom@link:../web/node_modules/react-dom::locator=%40standardnotes%2Ftoast%40workspace%3Apackages%2Ftoast" @@ -25948,15 +25869,6 @@ __metadata: languageName: node linkType: hard -"redux@npm:^4.2.0": - version: 4.2.0 - resolution: "redux@npm:4.2.0" - dependencies: - "@babel/runtime": ^7.9.2 - checksum: 75f3955c89b3f18edf5411e5fb482aa2e4f41a416183e8802a6bf6472c4fc3d47675b8b321d147f8af8e0f616436ac507bf5a25f1c4d6180e797b549c7db2c1d - languageName: node - linkType: hard - "reflect-metadata@npm:^0.1.13": version: 0.1.13 resolution: "reflect-metadata@npm:0.1.13"