DnD sortable
Qué añade esta funcionalidad
Enlace al encabezado@omnicajs/vue-remote/remote ahora exporta tres bloques para drag-and-drop sortable:
RemoteSortableContainerRemoteSortableItemRemoteDragHandle
Permiten que el código remoto describa listas y tableros ordenables, mientras que el adaptador Vue del host se encarga del hit-testing, del seguimiento del puntero, de la cancelación por teclado y de las actualizaciones del estado del DOM del lado host.
No necesitas registrar componentes host adicionales para esta funcionalidad. El runtime Vue del host ya entiende los bindings internos de DnD que emiten estos wrappers remotos.
Superficie del API remoto
Enlace al encabezadoimport { RemoteDragHandle, RemoteSortableContainer, RemoteSortableItem, type RemoteSortableEvent,} from '@omnicajs/vue-remote/remote'Props principales:
RemoteSortableContainercontainerId: clave lógica del contenedor.orientation:'vertical' | 'horizontal'.accepts?: valorestypeaceptados para los items.disabled?: desactiva el drop en el contenedor.onDragenter,onDragleave,onDragmove,onDrop.
RemoteSortableItemitemId: clave estable del item.containerId: clave del contenedor actual.index: índice actual en el orden visual.type: tipo del item usado poraccepts.payload?: payload serializable opcional devuelto en los eventos.disabled?: desactiva el drag para este item.onDragstart,onDragend,onDragcancel.
RemoteDragHandlefor?:itemIdexplícito que se debe arrastrar.disabled?: desactiva el inicio del puntero en el handle.
Los tres componentes también aceptan as, así que la raíz renderizada puede ser una etiqueta nativa o la raíz de un componente host.
Responsabilidades de host y remote
Enlace al encabezado- El código remoto declara contenedores, items, handles y la lógica de reorder.
- El runtime del host resuelve los elementos DOM reales detrás de esos nodos.
- El host mantiene la sesión del puntero y calcula
before,afteroinside. - La aceptación depende de
item.typey deacceptsen el contenedor destino. Escapecancela un drag activo y emiteonDragcancel.
Esta separación mantiene la lógica de reorder en el estado remoto, mientras que el trabajo de bajo nivel con el DOM queda en el lado host de confianza.
Ciclo de vida de eventos
Enlace al encabezadopointerdownsobreRemoteDragHandleinicia una sesión pendiente.- Después de cruzar el umbral de arrastre, se dispara
onDragstarten el item origen. - Mientras se mueve, el contenedor destino recibe
onDragenter,onDragmoveyonDragleave. - En
pointerupsobre un destino aceptado, el contenedor recibeonDrop. - El item origen siempre cierra con
onDragend, o cononDragcanceldespués deEscape/pointercancel.
RemoteSortableEvent contiene el estado normalizado del drag:
accepteditemId,type,payloadsourceContainerId,targetContainerIdtargetItemId,targetIndexplacementpointersessionId
Modelo de placement
Enlace al encabezadobeforeyafterse usan al pasar por el borde de un item existente.insidese usa al soltar dentro del propio contenedor, incluidos los contenedores vacíos.targetIndexya viene normalizado para el orden del contenedor destino.forenRemoteDragHandlees opcional si el handle se renderiza dentro del subtree del item arrastrado.
Ejemplo: backlog sortable en un SFC remoto
Enlace al encabezado<script setup lang="ts">import { ref } from 'vue'import { RemoteDragHandle, RemoteSortableContainer, RemoteSortableItem, type RemoteSortableEvent,} from '@omnicajs/vue-remote/remote'
type Task = { id: string; title: string;}
const tasks = ref<Task[]>([ { id: 'task-1', title: 'Design DnD contract' }, { id: 'task-2', title: 'Cover host runtime' }, { id: 'task-3', title: 'Ship docs' },])
const moveTask = (event: RemoteSortableEvent) => { if (!event.accepted || event.targetIndex == null) { return }
const fromIndex = tasks.value.findIndex(task => task.id === event.itemId)
if (fromIndex < 0) { return }
const [task] = tasks.value.splice(fromIndex, 1) const nextIndex = Math.min(event.targetIndex, tasks.value.length)
tasks.value.splice(nextIndex, 0, task)}</script>
<template> <RemoteSortableContainer as="ul" class="task-list" container-id="backlog" :accepts="['task']" orientation="vertical" :on-drop="moveTask" > <RemoteSortableItem v-for="(task, index) in tasks" :key="task.id" as="li" class="task-row" container-id="backlog" :index="index" :item-id="task.id" :payload="{ title: task.title }" type="task" > <RemoteDragHandle as="button" class="task-handle" :for="task.id" > Drag </RemoteDragHandle>
<span>{{ task.title }}</span> </RemoteSortableItem> </RemoteSortableContainer></template>Para un tablero tipo kanban, usa varios RemoteSortableContainer y actualiza los arrays de origen y destino dentro de onDrop.
Estado del DOM host para estilos
Enlace al encabezadoDurante el drag, el runtime del host añade atributos de estado al DOM real:
- Marcadores estáticos:
data-dnd-sortable-container,data-dnd-sortable-item,data-dnd-handle - Marcadores de sesión activa:
data-dnd-source,data-dnd-dragging,data-dnd-target,data-dnd-drag-over - Marcadores de placement y aceptación:
data-dnd-placement,data-dnd-drop-allowed,data-dnd-drop-forbidden
Eso permite estilizar el estado del drag desde CSS del host sin filtrar las props internas del transporte al DOM.