Skip to content

Primeros pasos

Instalación

Ingresa en tu terminal:

sh
# npm
npm i effdnd

# pnpm
pnpm add effdnd

# yarn
yarn add effdnd

Inicio rápido

En resumen, effdnd utiliza dos componentes web personalizados:

  • effdnd trigger activa la función de arrastrar y soltar,
  • effdnd-actor indica las áreas del diseño que participarán en el proceso de arrastrar y soltar (desempeñarán sus funciones).

El componente web effdnd-actor puede desempeñar varias funciones:

  • item: el elemento que se mueve,
  • target: el objetivo del movimiento,
  • scope: los límites del movimiento.

Para definir una función, debes establecer el atributo del mismo nombre en el elemento effdnd-actor. Se pueden asignar múltiples roles a un mismo elemento.

Al iniciar la función de arrastrar y soltar, el componente web effdnd-trigger utiliza sus atributos para seleccionar los participantes del proceso (actores):

  • El atributo item permite seleccionar el elemento que se va a mover. Si no se especifica, se utilizará el elemento más cercano en el árbol <effdnd-actor item='...'> con el atributo item especificado. Si se establece un atributo con el valor # (<effdnd-trigger item='#'>) o no existe ningún <effdnd-actor item='...'> en el árbol DOM superior, se moverá el propio activador.
  • El atributo scope permite seleccionar el área de movimiento disponible. Si no se especifica, se utilizará el elemento más cercano en el árbol <effdnd-actor scope='...'> con el atributo scope especificado. Si se establece un atributo con el valor # (<effdnd-trigger scope='#'>) o no existe un <effdnd-actor scope='...'> en el árbol DOM superior, el área de desplazamiento se considerará document.body.

El atributo target permite seleccionar los objetivos de movimiento disponibles. Estos objetivos generan eventos especiales cuando finaliza la operación de arrastrar y soltar sobre ellos. Todos los elementos <effdnd-actor target='...'> ubicados dentro del área scope se considerarán objetivos de movimiento, cuyos nombres comiencen con el valor del atributo target del activador. Esto significa que, si no se especifica el atributo, todos los <effdnd-actor target='...'> estarán disponibles dentro del <effdnd-actor scope='...'> actual.

Para definir ambos componentes web, simplemente llame a la función useDnD y utilice la escucha de eventos para detectar los resultados de la llamada:

jsx
import { useRef } from 'react';
import { useDnD } from 'effdnd';

const { observe } = useDnD();

export const Component = () => {
    const ref = useRef();
    useEffect(() => {
      // puedes suscribirte a eventos de arrastrar y soltar
      const unobserve = observe((e) => {
        // el evento se está procesando aquí
      }, ref.current);
      // y puedes darte de baja
      return () => unobserve();
    });
    return <effdnd-actor scope='top' ref={ref} >
        <div className="targets-wrapper">
            <effdnd-actor target='target-1'>...</effdnd-actor>
            <effdnd-actor target='target-2'>...</effdnd-actor>
        </div>
        <div id="items-wrapper">
            <effdnd-actor item='item-1'>
                <effdnd-trigger>Trigger #1</effdnd-trigger>
            </effdnd-actor>
            <effdnd-actor item='item-2'>
                <effdnd-trigger>Trigger #2</effdnd-trigger>
            </effdnd-actor>
        </div>
    </effdnd-actor>;
}

Elementos activos y pasivos

Durante la operación de arrastrar y soltar, el effdnd-trigger establece el atributo dinámico state en los actores effdnd-actor seleccionados. Es decir, al inicio, el trigger determina qué se mueve (item), dónde puede moverse (scope) y dónde debe moverse (target). Los elementos pueden estar:

  • sin estado,
  • en estado pasivo (state="passive"),
  • en estado activo (state="active").

El elemento con el rol item está activo mientras se mueve. Además, un elemento con el rol item puede estar en estado clonado (state="cloned") si su clon está activo. Para clonar un elemento, active el modo item-mode="cloned".

Un elemento con el rol scope está pasivo cuando el item se mueve dentro de él. Este estado delimita el área de desplazamiento.

Un elemento con el rol de ámbito se activa si se encuentra en estado pasivo y el elemento intenta sobrepasarlo. Este estado indica al usuario que el cursor se ha movido más allá de los límites permitidos.

Un elemento con el rol de destino se encuentra en estado pasivo cuando está dentro de un ámbito con estado activo o pasivo. Este estado muestra dónde se puede mover el elemento.

Un elemento con el rol de destino se activa si se encuentra en estado pasivo y el cursor con el elemento está sobre él. Este estado indica que el destino se está preparando para aceptar el elemento.

Modos de rol

El comportamiento básico de la biblioteca es de bajo nivel, por lo que es posible refinar el caso de uso mediante el modo de cada rol:

  • item-mode define el modo de item y permite establecer los siguientes valores:
    • item-mode="keep": el elemento item conservará sus nuevas coordenadas tras moverse;
    • item-mode="clone": se creará un clon del elemento item, que se moverá;
  • target-mode define el modo de target tras seleccionarlo y permite establecer los siguientes valores:
    • target-mode="prepend": el elemento item se añadirá al target como primer elemento hijo;
    • target-mode="append": el elemento item se añadirá al target como último elemento hijo; - target-mode="remove": el elemento item se eliminará del árbol DOM;
  • scope-mode define el modo de scope durante la operación de arrastrar y soltar, y puede establecer los siguientes valores:
    • scope-mode="order-x": el elemento scope permite reorganizar los elementos item a lo largo del eje x;
    • scope-mode="order-y": el elemento scope permite reorganizar los elementos item a lo largo del eje y.

Estilos

La apariencia de <effdnd-actor item='...'> se define mediante el activador utilizando atributos durante el movimiento. También puedes usar atributos para configurar los parámetros de animación, el eje de movimiento y la distancia mínima de disparo.

ts
/export interface ITriggerAttrs {
    /**
     * Item name
     * @description
     * If the value is "#" then it will use `effnd-trigger` as item
     */
    item?: string;
    /**
     * Bounding scope name
     * @description
     * If the value is "#" then it will use `document.body` as scope
     */
    scope?: string;
    /**
     * Target name or its prefix
     */
    target?: string;
    /**
     * Triggering distance
     */
    dist?: string;
    /**
     * Triggering mouse button
     * @description
     * Any mouse button if not specified
     */
    btn?: '0' | '1' | '2';
    /**
     * DnD axis
     */
    axis?: string;
    /**
     * Triggering event
     * @description
     * Both 'touch' and 'mouse' by default
     */
    event?: 'touch' | 'mouse';
    /**
     * Transition duration
     */
    dur?: string;
    /**
     * Transition delay
     */
    del?: string;
    /**
     * Transition timing-function
     */
    tf?: string;
}

Por defecto, se utilizará un icono de movimiento SVG dentro del activador vacío, cuya apariencia depende del atributo axis. Para ocultar el icono, utilice su propio contenido dentro del effdnd-trigger.

El componente web effdnd-actor ya incluye los estilos iniciales para los estados pasivo y activo de los roles, pero también permite eliminarlos mediante el atributo unstyled. <effdnd-actor unstyled="target"> elimina únicamente los estilos integrados de target, <effdnd-actor unstyled="scope"> elimina únicamente los estilos integrados de scope, y <effdnd-actor unstyled> elimina todos los estilos integrados.

ts
/**
 * DnD actor attributes
 */
export interface IActorAttrs {
    /**
     * Item name
     */
    item?: string;
    /**
     * Scope name
     */
    scope?: string;
    /**
     * Target name
     */
    target?: string;
    /**
     * Actor state
     */
    state?: 'active' | 'passive';
    /**
     * Reset target state styles
     */
    unstyled?: boolean | 'target' | 'scope';
    /**
     * Display contents
     */
    contents?: boolean;
    /**
     * Item mode
     */
    'item-mode'?: 'keep' | 'clone';
    /**
     * Target mode
     */
    'target-mode'?: 'append' | 'prepend' | 'remove';
    /**
     * Scope mode
     */
    'scope-mode'?: 'order-x' | 'order-y';
    /**
     * Scope transition duration
     */
    'scope-dur'?: number;
    /**
     * Scope transition delay
     */
    'scope-del'?: number;
    /**
     * Scope transition timing-function
     */
    'scope-tf'?: string;
}

Los atributos scope-dur, scope-del y scope-del para un elemento con el rol scope establecen los valores predeterminados de la propiedad CSS transition.

El atributo contents permite establecer el estilo display:contents;.

También puedes definir tus propios estilos CSS para diferentes estados:

css
effdnd-actor[target][state=passive] .custom-dnd-target {
  outline: 4px solid #646cffaa;
}
effdnd-actor[target][state=active] .custom-dnd-target {
  outline: 4px solid #646cffaa;
  background: #646cffaa;
}

Renderizado del lado del servidor

Si utilizas el renderizado del lado del servidor, simplemente añade un script con la declaración effdnd a la cabecera de tu HTML para mantener el diseño:

html
<head>
    <script src="https://cdn.jsdelivr.net/npm/effdnd@3.1.0/dist/use.js"></script>
</head>

Este script también te permitirá usar effdnd como variable global:

ts
import { TUseDnD } from 'effdnd';

declare global {
    interface Window {
        effdnd: ReturnType<TUseDnD>;
    }
};

const unobserve = window.effdnd.observe(() => console.log('effdnd'));

useDnD

La función declara los componentes web effdnd-trigger y effdnd-actor, y también devuelve manejadores para suscribirse a eventos personalizados:

ts
export type TEventDetail = {
    type: TEventType;
    refs: TRefs;
    keys: TKeys;
    event: MouseEvent | TouchEvent;
};

interface TDnDEvent extends CustomEvent {
    detail: TEventDetail;
}

export type TDnDCallback = (event: TDnDEvent) => void;

export type TUseDnD = () => {
    /**
     * Observar eventos DnD
     * @param callback - controlador de eventos
     * @param element - elemento HTML
     */
    observe: (callback: TDnDCallback, element?: HTMLElement) => () => void;
    /**
     * No observar eventos DnD
     * @param callback - controlador de eventos
     * @param element - elemento HTML
     */
    unobserve: (callback: TDnDCallback, element?: HTMLElement) => void;
};

effdnd-trigger

El componente web de activación contiene varios métodos y propiedades útiles:

ts
/**
 * Elemento disparador DnD
 */
export interface ITriggerElement extends HTMLElement {
    /**
     * Está activo el disparador
     */
    isActive: boolean;
    /**
     * Artículo y-desplazamiento
     */
    dndY: number;
    /**
     * Artículo x-desplazamiento
     */
    dndX: number;
    /**
     * Artículo DnD
     */
    dndItem: HTMLElement;
    /**
     * Alcance DnD
     */
    dndScope: HTMLElement;
    /**
     * Objetivos DnD
     */
    dndTargets: Set<HTMLElement>;
    /**
     * Restablecer DnD traducir
     */
    resetDnD(): void;
}

Publicado bajo la Licencia Apache 2.0