debug: task dnd 기능이 obsidian의 자체 dnd를 방해하던 버그를 해결

This commit is contained in:
sechan100 2024-12-25 10:30:50 +09:00
parent 4e59ec3277
commit 3a67ffdf87
9 changed files with 91 additions and 33 deletions

View file

@ -0,0 +1,26 @@
import { HTML5BackendImpl } from 'node_modules/react-dnd-html5-backend/dist/HTML5BackendImpl';
import { DragDropManager } from 'dnd-core';
import { HTML5BackendContext, HTML5BackendOptions } from 'react-dnd-html5-backend';
import { isTaskElDragItemType } from './drag-item';
class CustomHTML5BackendImpl extends HTML5BackendImpl {
constructor(manager: DragDropManager, globalContext?: HTML5BackendContext, options?: HTML5BackendOptions){
super(manager, globalContext, options);
const originalHandleTopDropCapture = this.handleTopDropCapture;
this.handleTopDropCapture = (e: DragEvent) => {
const monitor = manager.getMonitor();
const type = monitor.getItemType();
if(typeof type === "string" && isTaskElDragItemType(type)){
originalHandleTopDropCapture(e);
}
}
}
}
export const CustomHTML5Backend = (manager: DragDropManager, context: HTML5BackendContext, options: HTML5BackendOptions) => {
return new CustomHTML5BackendImpl(manager, context, options);
};

View file

@ -0,0 +1,26 @@
import { DragDropManager } from 'dnd-core';
import { HTML5BackendContext, HTML5BackendOptions } from 'react-dnd-html5-backend';
import { isTaskElDragItemType } from './drag-item';
import { TouchBackendContext, TouchBackendImpl, TouchBackendOptions } from 'react-dnd-touch-backend';
class CustomTouchBackendImpl extends TouchBackendImpl {
constructor(manager: DragDropManager, globalContext: TouchBackendContext, options: Partial<TouchBackendOptions>){
super(manager, globalContext, options);
const originalHandleTopMoveEndCapture = this.handleTopMoveEndCapture;
this.handleTopMoveEndCapture = (e: Event) => {
const monitor = manager.getMonitor();
const type = monitor.getItemType();
if(typeof type === "string" && isTaskElDragItemType(type)){
originalHandleTopMoveEndCapture(e);
}
}
}
}
export const CustomTouchBackend = (manager: DragDropManager, globalContext: TouchBackendContext, options: Partial<TouchBackendOptions>) => {
return new CustomTouchBackendImpl(manager, globalContext, options);
};

View file

@ -10,11 +10,13 @@ import {
createTransition,
} from "react-dnd-multi-backend";
import { Preview } from "react-dnd-preview";
import { ElementPreview } from "./ElementPreview";
import { useDndScroll } from "../dnd/use-dnd-scroll";
import { ElementPreview } from "../ui/ElementPreview";
import { useDndScroll } from "./use-dnd-scroll";
import { useDragDropManager } from "react-dnd";
import { TaskElDragItem } from '../dnd/drag-item';
import { TaskElDragItem } from './drag-item';
import { isNoteElement, isTaskGroup } from "@entities/note";
import { CustomHTML5Backend } from "./CustomHTML5BackendImpl";
import { CustomTouchBackend } from "./CustomTouchBackendImpl copy";
export const DELAY_TOUCH_START = 1000;
@ -36,27 +38,25 @@ export const TaskDndContext = ({ children }: {children: React.ReactNode }) => {
}), [setBackend])
const HTML5toTouch: MultiBackendOptions = useMemo<MultiBackendOptions>(() => {
return {
backends: [
{
id: "html5",
backend: HTML5Backend,
transition: MouseTransition,
const HTML5toTouch: MultiBackendOptions = useMemo<MultiBackendOptions>(() => ({
backends: [
{
id: "html5",
backend: CustomHTML5Backend,
transition: MouseTransition,
},
{
id: "touch",
backend: CustomTouchBackend,
options: {
enableMouseEvents: false,
delayTouchStart: DELAY_TOUCH_START,
ignoreContextMenu: false
},
{
id: "touch",
backend: TouchBackend,
options: {
enableMouseEvents: false,
delayTouchStart: DELAY_TOUCH_START,
ignoreContextMenu: false
},
transition: TouchTransition
},
],
}
}, [MouseTransition, TouchTransition])
transition: TouchTransition,
},
],
}), [MouseTransition, TouchTransition])
return (
<DndProvider options={HTML5toTouch}>
@ -64,9 +64,9 @@ export const TaskDndContext = ({ children }: {children: React.ReactNode }) => {
{children}
</ScrollComponent>
<div className="dr-task-preview-context">
<Preview generator={({ item, style }) => {
<Preview generator={({ item, style, itemType }) => {
// @ts-ignore
if(item.el !== undefined && isNoteElement(item.el)){
if(item.el !== undefined && isNoteElement(item.el) && itemType !== "__NATIVE_TEXT__"){
return (
<ElementPreview
item={item as TaskElDragItem}
@ -100,6 +100,7 @@ const ScrollComponent = ({ children }: ScrollComponentProps) => {
const offset = monitor.getSourceClientOffset()?.y as number;
updatePosition({ position: offset, isScrollAllowed: true });
});
return unsubscribe;
}, [monitor, updatePosition]);

View file

@ -2,4 +2,9 @@ import { NoteElement } from "@entities/note";
export interface TaskElDragItem {
el: NoteElement;
}
export type TaskElDragItemType = "TASK" | "GROUP";
export const isTaskElDragItemType = (type: string): type is TaskElDragItemType => {
return type === "TASK" || type === "GROUP";
}

View file

@ -3,7 +3,7 @@ import { RoutineNote, Task, NoteElement, TaskGroup } from "@entities/note";
import { useLeaf } from "@shared/view/use-leaf";
import React, { RefObject, useCallback, useEffect, useMemo, useReducer, useState } from "react";
import { DropTargetMonitor, useDrag, useDrop } from "react-dnd";
import { TaskElDragItem } from "./drag-item";
import { TaskElDragItem, TaskElDragItemType } from "./drag-item";
import { GroupHitArea, HitAreaEvaluator } from "./hit-area";
import { DndIndicator } from "./indicator";
import { DroppedElReplacer } from "../model/reorder-elements";
@ -22,7 +22,7 @@ interface UseGroupDndResult {
isDragging: boolean;
indicator: React.ReactNode | null;
}
export const useGroupDnd = ({
export const useGroupDnd = ({
group,
groupRef,
isGroupOpen,
@ -38,7 +38,7 @@ export const useGroupDnd = ({
}, [hit])
const [{ isDragging }, drag, preview] = useDrag({
type: "GROUP",
type: "GROUP" as TaskElDragItemType,
item: () => ({
el: group,

View file

@ -7,7 +7,7 @@ import { DropTargetMonitor, useDrag, useDrop } from "react-dnd";
import { HitAreaEvaluator, TaskHitArea } from "./hit-area";
import { DndIndicator } from "./indicator";
import { DroppedElReplacer } from "../model/reorder-elements";
import { TaskElDragItem } from "./drag-item";
import { TaskElDragItem, TaskElDragItemType } from "./drag-item";
import { useRoutineMutationMerge } from "@features/merge-note";
@ -57,7 +57,7 @@ export const useTaskDnd = ({
}, [group, task.name])
const [{ isDragging }, drag, preview] = useDrag({
type: "TASK",
type: "TASK" as TaskElDragItemType,
item: () => ({
el: task,

View file

@ -1,4 +1,4 @@
export { TaskDndContext } from "./ui/dnd-context";
export { TaskDndContext } from "./dnd/dnd-context";
export { BaseTaskFeature } from "./ui/BaseTaskFeature";
export { BaseTaskGroupFeature } from "./ui/BaseTaskGroupFeature";
export { renderTask } from "./ui/render-task-widget";

View file

@ -11,7 +11,7 @@ import { CancelLineName } from './CancelLineName';
import { Checkbox } from './Checkbox';
import { OptionIcon } from './OptionIcon';
import { baseHeaderStyle, dragReadyStyle, draggingStyle, elementHeight, pressedStyle } from './base-element-style';
import { DELAY_TOUCH_START } from './dnd-context';
import { DELAY_TOUCH_START } from '../dnd/dnd-context';
import { Menu } from 'obsidian';

View file

@ -8,7 +8,7 @@ import { useLeaf } from '@shared/view/use-leaf';
import React, { useCallback, useEffect, useRef, useState } from "react";
import { useGroupDnd } from '../dnd/use-group-dnd';
import { baseHeaderStyle, draggingStyle, dragReadyStyle, elementHeight, pressedStyle } from './base-element-style';
import { DELAY_TOUCH_START } from './dnd-context';
import { DELAY_TOUCH_START } from '../dnd/dnd-context';
import { OptionIcon } from './OptionIcon';
import { CancelLineName } from './CancelLineName';
import { renderTask } from './render-task-widget';