React-dnd: Una forma de arrastrar al exterior al iframe

Creado en 1 ago. 2019  ·  6Comentarios  ·  Fuente: react-dnd/react-dnd

¿Su solicitud de función está relacionada con un problema?
Reaccionar límites que arrastran y sueltan dentro de un solo documento HTML. De alguna manera necesitamos arrastrar algo afuera al iframe adentro.

Describe la solución que te gustaría
Encuentro que dnd HTML5backend solo activa las devoluciones de llamada de arrastre en la ventana. Entonces, si podemos hacer que los componentes dentro del iframe activen esas devoluciones React.createPortal llamada, y

import React, {
  useRef,
  useEffect,
  useContext,
  forwardRef,
} from 'react';
import classnames from 'classnames';
import { DndContext } from 'react-dnd';

// Frame base on createPortal inside iframe dom.
import Frame from 'react-frame-component';

const events = [
  ['dragstart', 'handleTopDragStart', false],
  ['dragstart', 'handleTopDragStartCapture', true],
  ['dragend', 'handleTopDragEndCapture', true],
  ['dragenter', 'handleTopDragEnter', false],
  ['dragenter', 'handleTopDragEnterCapture', true],
  ['dragleave', 'handleTopDragLeaveCapture', true],
  ['dragover', 'handleTopDragOver', false],
  ['dragover', 'handleTopDragOverCapture', true],
  ['drop', 'handleTopDrop', false],
  ['drop', 'handleTopDropCapture', true],
];

export const DndFrame = forwardRef((props = {}, ref) => {
  const container = useRef(null);
  const dndValue = useContext(DndContext) || {};

  const { dragDropManager: { backend = {} } = {} } = dndValue;
  const { children, className, containerProps = {}, ...others } = props;

  const cls = classnames({
    'dnd-frame': true,
    [className]: !!className,
  });

  useEffect(() => {
    const { current } = container;

    if (!current) {
      return;
    }

    // this make callback run in outside window
    events.forEach((eventArgs = []) => {
      const [name, callbackName, capture = false] = eventArgs;

      const callback = backend[callbackName] && backend[callbackName].bind(backend);

      current.addEventListener(name, (...args) => {
        callback && callback(...args);
      }, capture);
    });
  }, [container.current]);

  return (
    <Frame className={cls} ref={ref} {...others}>
      <div className="dnd-frame-container" ref={container} {...containerProps}>
        { children }
      </div>
    </Frame>
  );
});

Describe las alternativas que has considerado
Puede exportar algunas opciones con HTML5Backend.

design decisions enhancement pinned

Comentario más útil

Encontré una solución más fácil para simplificar este código, pero no estoy seguro si esta es una mejor solución. Espero ayudarlo a solucionar este problema.

import React, { useContext, useEffect } from 'react';
import DndProvider, { DndContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import Frame, { FrameContext } from 'react-frame-component';

const DndFrame = ({ children }) => {
  const { dragDropManager } = useContext(DndContext);
  const { window } = useContext(FrameContext);

  useEffect(() => {
    dragDropManager.getBackend().addEventListeners(window);
  });

  return children;
};

const Example = () => (
  <DndProvider backend={HTML5Backend}>
    <Frame>
       <DndFrame>
          <div>...</div>
       </DndFrame>
    </Frame>
  </DndProvider>
);

Todos 6 comentarios

Encontré una solución más fácil para simplificar este código, pero no estoy seguro si esta es una mejor solución. Espero ayudarlo a solucionar este problema.

import React, { useContext, useEffect } from 'react';
import DndProvider, { DndContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import Frame, { FrameContext } from 'react-frame-component';

const DndFrame = ({ children }) => {
  const { dragDropManager } = useContext(DndContext);
  const { window } = useContext(FrameContext);

  useEffect(() => {
    dragDropManager.getBackend().addEventListeners(window);
  });

  return children;
};

const Example = () => (
  <DndProvider backend={HTML5Backend}>
    <Frame>
       <DndFrame>
          <div>...</div>
       </DndFrame>
    </Frame>
  </DndProvider>
);

@HsuTing Es más fácil y mejor. Pero aún vinculado a la interfaz HTML5Backend. Si HTML5Backend cambia addEventListeners => addListeners, nuestra web se romperá

Una idea realmente genial, jugaré con ella cuando regrese de la caminata.

El martes 6 de agosto de 2019 a las 11:43 p.m. 晓 爽[email protected] escribió:

@HsuTing https://github.com/HsuTing Es más fácil y mejor. Pero aún
enlazado a la interfaz HTML5Backend. Si HTML5Backend cambia addEventListeners
=> addListeners, nuestra web se rompería

-
Está recibiendo esto porque fue asignado.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/react-dnd/react-dnd/issues/1496?email_source=notifications&email_token=AAA3XCDZJS3V5E7YISDRUC3QDJVJLA5CNFSM4IIMWOQ2YY3PNVWWK3TUL52HS4DVDMVREXWWK3TUL52HS4DFZVLOXWG43 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AAA3XCGHNHO3M3CSL5VRUQTQDJVJLANCNFSM4IIMWOQQ
.

Encontré una solución más fácil para simplificar este código, pero no estoy seguro si esta es una mejor solución. Espero ayudarlo a solucionar este problema.

import React, { useContext, useEffect } from 'react';
import DndProvider, { DndContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import Frame, { FrameContext } from 'react-frame-component';

const DndFrame = ({ children }) => {
  const { dragDropManager } = useContext(DndContext);
  const { window } = useContext(FrameContext);

  useEffect(() => {
    dragDropManager.getBackend().addEventListeners(window);
  });

  return children;
};

const Example = () => (
  <DndProvider backend={HTML5Backend}>
    <Frame>
       <DndFrame>
          <div>...</div>
       </DndFrame>
    </Frame>
  </DndProvider>
);

Es un gran enfoque y me funciona.

Encontré una solución más fácil para simplificar este código, pero no estoy seguro si esta es una mejor solución. Espero ayudarlo a solucionar este problema.

import React, { useContext, useEffect } from 'react';
import DndProvider, { DndContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import Frame, { FrameContext } from 'react-frame-component';

const DndFrame = ({ children }) => {
  const { dragDropManager } = useContext(DndContext);
  const { window } = useContext(FrameContext);

  useEffect(() => {
    dragDropManager.getBackend().addEventListeners(window);
  });

  return children;
};

const Example = () => (
  <DndProvider backend={HTML5Backend}>
    <Frame>
       <DndFrame>
          <div>...</div>
       </DndFrame>
    </Frame>
  </DndProvider>
);

Cuando intento con mecanografiado, obtengo un error Property 'addEventListeners' does not exist on type 'Backend'

¿Hay alguna forma de solucionar esto en TS?

addEventListeners no está expuesto en la interfaz Backend; y no quiero exponerlo porque es específico de DOM / navegador. Creo que lo que probablemente deberíamos hacer es algo como:

// detect if SSR mode
const DEFAULT_GLOBAL_CONTEXT = typeof window !== 'undefined' ? window : global

const DndFrame = ({ children, globalContext = DEFAULT_GLOBAL_CONTEXT}) => {
  const { dragDropManager } = useContext(DndContext);
  const { window } = useContext(FrameContext);
  const backend = useMemo(() => dragDropManager.getBackend(), [dragDropManager])

  useEffect(() => {
     // This will required adding an initialize() method to the Backend interface.
    // Backend constructors will have to thunk over to it. It could replace constructors, but that would be semver major.
    backend.initialize(dragDropManager, globalContext)
    backend.setup()
  }, [globalContext]);

  return children;
};

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

gaearon picture gaearon  ·  4Comentarios

djeremh picture djeremh  ·  3Comentarios

BrennanRoberts picture BrennanRoberts  ·  3Comentarios

Okami92 picture Okami92  ·  3Comentarios

redochka picture redochka  ·  3Comentarios