React-dnd: Uma forma de arrastar para fora para o iframe

Criado em 1 ago. 2019  ·  6Comentários  ·  Fonte: react-dnd/react-dnd

Sua solicitação de recurso está relacionada a um problema?
O React limita o processo de arrastar e soltar em um único documento HTML. De alguma forma, precisamos arrastar algo para fora para o iframe dentro.

Descreva a solução que você gostaria
Acho que dnd HTML5backend apenas aciona callbacks de arrastar na janela. Portanto, se pudermos fazer os componentes dentro do iframe acionar esses callbacks. E React.createPortal fazer os componentes dentro do iframe ter o mesmo DndProvider com fora. Funciona, felizmente. Mas eu me preocupo com alguns problemas que não percebi. E o código não é tão conveniente com HTML5Backend.

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>
  );
});

Descreva as alternativas que você considerou
Você pode exportar algumas opções com HTML5Backend.

design decisions enhancement pinned

Comentários muito úteis

Eu encontrei uma solução mais fácil para simplificar este código, mas não tenho certeza se esta é a melhor solução. Espero ajudá-lo a corrigir esse 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 comentários

Eu encontrei uma solução mais fácil para simplificar este código, mas não tenho certeza se esta é a melhor solução. Espero ajudá-lo a corrigir esse 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 É mais fácil e melhor. Mas ainda vinculado à interface HTML5Backend. Se HTML5Backend alterar addEventListeners => addListeners, nossa web será quebrada

Uma ideia muito legal, vou brincar com ela quando voltar da caminhada

Na terça-feira, 6 de agosto de 2019, 23h43 晓 爽[email protected] escreveu:

@HsuTing https://github.com/HsuTing É mais fácil e melhor. Mas ainda
vinculado à interface HTML5Backend. Se HTML5Backend mudar addEventListeners
=> addListeners, nossa web seria quebrada

-
Você está recebendo isto porque foi designado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/react-dnd/react-dnd/issues/1496?email_source=notifications&email_token=AAA3XCDZJS3V5E7YISDRUC3QDJVJLA5CNFSM4IIMWOQ2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD3XL66Y#issuecomment-518963067 ,
ou silenciar o tópico
https://github.com/notifications/unsubscribe-auth/AAA3XCGHNHO3M3CSL5VRUQTQDJVJLANCNFSM4IIMWOQQ
.

Eu encontrei uma solução mais fácil para simplificar este código, mas não tenho certeza se esta é a melhor solução. Espero ajudá-lo a corrigir esse 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>
);

É uma ótima abordagem e funciona para mim.

Eu encontrei uma solução mais fácil para simplificar este código, mas não tenho certeza se esta é a melhor solução. Espero ajudá-lo a corrigir esse 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>
);

Ao tentar com o texto digitado, obtenho um erro Property 'addEventListeners' does not exist on type 'Backend'

existe alguma maneira de consertar isso no TS?

addEventListeners não é exposto na interface de back-end; e não quero expô-lo porque é específico do DOM / navegador. Acho que provavelmente deveríamos fazer 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;
};

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

user1736 picture user1736  ·  3Comentários

bebbi picture bebbi  ·  3Comentários

djeremh picture djeremh  ·  3Comentários

Okami92 picture Okami92  ·  3Comentários

gocreating picture gocreating  ·  4Comentários