Montaje, colecciones y scroll horizontal Web
Disponible desde 0.1.0-rc.8. Estas adiciones resuelven #334, #336 y #337. El runtime experimental /web funciona directamente o con Vue, sin otro motor en los componentes.
Vue y Nuxt: esperar la conexión
mounted no garantiza la inserción en el documento. Nuxt out-in y Suspense pueden montar una rama separada. createViewportEnterDirective() observa su conexión real, sin temporizador fijo ni sondeo por frame. Cree una directiva por aplicación/solicitud SSR y úsela sobre HTML.
import { createViewportEnterDirective } from '@rafaelaugusto/jolt/web/vue'
export default defineNuxtPlugin((nuxt) => {
nuxt.vueApp.directive(
'enter',
createViewportEnterDirective({
viewport: {
keyframes: { opacity: [0, 1], y: [24, 0] },
transition: { duration: 350 },
},
}),
)
})<template><section v-enter>Content</section></template>La fábrica es segura en SSR y no oculta contenido del servidor. runtime toma prestado el contexto del host; config configura el propio y viewport aporta valores predeterminados. El binding los sobrescribe; sustituya su objeto para cambiar la receta. Desmontar cancela la espera y desconectar libera solo esa entrada. KeepAlive reconstruye entradas incompletas/repetidas y conserva las únicas completadas. Cambiar el binding reinicia ese historial. Se observa un ShadowRoot conocido y su host; trasladar a una raíz cerrada desconocida queda fuera del contrato.
useWebMotion().use() y las entradas de transición esperan la inserción. Cambiar referencias, desactivar, cancelar o destruir elimina la espera. Las llamadas imperativas animate(), set() y runtime.viewportEnter() siguen exigiendo elementos montados. Resuelva datos asíncronos antes del callback síncrono del scope.
Para una transición de página que solo cambia la opacidad y cuyo contenido asíncrono modifica la altura, declara transform-origin: 0 0 en la superficie, como en el ejemplo Nuxt. El origen porcentual cambia al crecer la caja. Si el transform necesita un pivote adaptable, utiliza observeGeometry() del runtime; esperar la inserción no concede control sobre cambios externos de geometría.
El consumidor empaquetado Nuxt 4.6.3/Vue 3.5.44 verifica SSR, historial, inserción diferida, KeepAlive y movimiento reducido en tres navegadores. Interrumpir una ruta asíncrona durante out-in puede dejar un placeholder vacío incluso con CSS puro; el adapter no corrige esa limitación del router. La cancelación Vue se prueba por separado. Consulte el informe.
Identidad de datos al reciclar filas
animateItems() controla entradas; no virtualiza ni reordena con FLIP. Las claves únicas son strings, números finitos u objetos. Los elementos también deben ser únicos y estar montados. Se valida todo el lote antes de cambiar ownership. En Vue actualice tras nextTick() o con un watcher post-flush.
const rows = runtime.animateItems([{ key: item.id, target: rowElement }], 'fadeInUp', {
root: scroller,
once: true,
duration: 400,
})
// After the renderer has committed the next DOM rows:
rows.update(nextItems.map((item) => ({ key: item.id, target: elements.get(item.id)! })))
rows.forget(item.id)
rows.suspend()
rows.resume()
rows.dispose()El valor predeterminado once: false permite reentrada. Con once: true, el historial pertenece a la clave: una nueva clave en el mismo DOM entra; una conocida en otro DOM recibe el destino. Los objetos usan referencias débiles; las claves primitivas duran hasta forget(key), forget() o dispose. Elimine claves expulsadas de la caché. Reordenar conserva el movimiento del mismo par clave/elemento. Quitar filas detiene solo su entrada. stagger se rechaza: use viewportEnter() para grupos y animateLayout() para FLIP.
pending, completed, suspended y disposed describen el controlador. Una colección vacía acepta filas nuevas. Un grupo de observers atiende todas las filas y se desconecta al completar entradas únicas. Sin IntersectionObserver, con movimiento reducido o deshabilitado, el contenido sigue visible. Scopes y suspensión conservan canales nuevos y press independiente.
Scroll horizontal LTR y RTL
const offset = runtime.scrollValue(rail, { axis: 'x' })
const progress = offset.to([0, 600], [0, 1])
const link = runtime.scrollLinked(
rail,
indicator,
{ scaleX: [0.02, 1] },
{
axis: 'x',
range: [0, 600],
execution: 'auto',
},
)
// After application geometry changes:
offset.refresh()
link.refresh()
// On teardown:
link.dispose()
progress.dispose()
offset.dispose()El eje predeterminado sigue siendo y. axis: x mide píxeles CSS desde el inicio lógico: izquierda en LTR, derecha en RTL. Se normaliza el scrollLeft negativo y se limita overscroll. Documento y elemento comparten contrato. Dirección, clases, estilos, contenido, tamaño y fuentes invalidan geometría; use refresh() para otros cambios.
El playback elegible usa ScrollTimeline. execution: scheduler fuerza el fallback compartido; se comparan extremos y retorno LTR/RTL. Composición, reemplazo parcial, movimiento reducido y limpieza conservan ownership. No quedan frames en reposo. Flex invertido en el eje elegido y escritura vertical se rechazan antes de adquirir propiedades. No se promete igualdad entre píxeles CSS, DIPs y convenciones RTL nativas.