import { usePinch, useGesture, useDrag } from '@use-gesture/react'
import { useSpring, animated } from '@react-spring/web'
import { useMemo } from 'react';
import { useDispatch } from 'react-redux';
import { appActions } from '../../redux';
import { uuid } from '../../_core';
/**
* Componente contenedor que utiliza gestos de arrastre,
* para actualizar una variable segun la direccion en la que se arrastró el elemento
* @name Reactor.Components.Input.Gesture
* @param {string!} name
* El nombre o identificador del elemento
* @param {string} [distance = "5"]
* Distancia en pixeles en la que se producirá el evento
* @param {string} [directions = "lrtb"]
* Direcciones en las que se puede mover el div para generar gestos
* @param {string?} variable Nombre de la variable que se va a actualizar
* @param {string?} context Nombre del contexto que contiene la variable
* @param {"true"|"false"} [storage = "false"] Si es true el dato se guarda en el storage del explorador
* @param {"true"|"false"} [debug = "false"] Si es true se obtendra una salida en la consola del navegador cuando se produzca un evento
* @class
* @returns {string} [name]-[direction]-[guid]
* @example
<div style="width: 200px; display: flex; align-items: center; height: 200px; justify-content: center;">
<gesture name="id_item_1" variable="accion" context="test_gesture" debug="true" distance="25" directions="lr">
<div style="background-color: red; width: 30px; height: 30px; border-radius: 5px; margin: 5px"></div>
</gesture>
<gesture name="id_item_2" variable="accion" context="test_gesture" debug="true" distance="25" directions="tb">
<div style="background-color: blue; width: 30px; height: 30px; border-radius: 5px; margin: 5px"></div>
</gesture>
<gesture name="id_item_3" variable="accion" context="test_gesture" debug="true" distance="25">
<div style="background-color: green; width: 30px; height: 30px; border-radius: 5px; margin: 5px"></div>
</gesture>
<gesture name="id_item_4" variable="accion" context="test_gesture" debug="true" distance="25">
<div style="background-color: yellow; width: 30px; height: 30px; border-radius: 5px; margin: 5px"></div>
</gesture>
</div>
*/
export const Gesture = ({name, distance = "5", directions = "lrtb", variable, context, storage = "false", debug = "false", children}) => {
const dist = useMemo(() => parseInt(distance), [distance]);
const dispatch = useDispatch();
const [{ x, y }, api] = useSpring(() => ({ x: 0, y: 0 }));
const dirs = useMemo(()=>({
left: directions.includes("l"),
right: directions.includes("r"),
top: directions.includes("t"),
bottom: directions.includes("b")
}), [directions]);
// Set the drag hook and define component movement based on gesture data
const bind = useDrag(
(state) => {
const { active, direction: [dirX, dirY], distance: [disX, disY], canceled, cancel, down, movement: [mx, my] } = state;
if(!down){
cancel();
}
if(
!dirs.left && mx < 0 ||
!dirs.top && my < 0 ||
!dirs.right && mx > 0 ||
!dirs.bottom && my > 0
) {
cancel();
return;
}
const fireEventLeft = down && !canceled && mx < -dist;
const fireEventRight = down && !canceled && mx > dist;
const fireEventTop = down && !canceled && my < -dist;
const fireEventBottom = down && !canceled && my > dist;
if(fireEventLeft || fireEventRight || fireEventTop || fireEventBottom){
const event = fireEventLeft
? "left"
: (fireEventRight
? "rigth"
: (fireEventTop
? "top"
: (fireEventBottom
? "bottom"
: "")));
const newValue = `${name}-${event}-${uuid().replaceAll('-', '')}`;
dispatch(appActions.setVariable(variable, newValue, context, storage === "true"));
cancel();
debug === "true" && console.log({mx, my, down, canceled, event: newValue, variable, context});
}
api.start({
x: active ? mx : 0,
y: active ? my : 0,
immediate: active
});
},
{
axis: 'lock',
threshold: 20,
rubberband: 1,
bounds: { left: -dist, right: dist, top: -dist, bottom: dist }
}
)
return <animated.div {...bind()} style={{ x, y, touchAction: "none"}}>{children}</animated.div>
}