Source: templates/ToggleVariable.js

import React, { useContext, useEffect, useRef, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { processOptions, FormContext } from "../..";
import { appActions } from "../../redux";
const safeEval = require('safe-eval-2')

/**
 * Componente que responde al evento click
 * @name Reactor.Components.Templates.ToggleVariable
 * @param {string!} variable Nombre de la variable
 * @param {string} [context = "global"] Nombre del contexto a usar
 * @param {(string|JsonString)} on Valor cuando esta on (puede ser json string para setear un objeto en la variable)
 * @param {(string|JsonString)} off Valor cuando esta off (puede ser json string para setear un objeto en la variable)
 * @param {BooleanString} [prevent_default = "true"] True para cortar evitar que el evento click se envie a los componente hijos
 * @param {JsonString} options Json string con los atributos que se quieran enviar al div contenedor
 * @param {("on"|"off")} [default_state = "off"] Estado por default del componente (setea la variable al renderizarse)
 * @param {BooleanString} [use_event = "false"] Indica si se envia un evento al form que lo contiene
 * @class 
 * @example 
<toggle_variable 
  variable="type_password" 
  on="text" off="password" 
  context="login" 
  prevent_default="true" 
  default_state="off" 
  use_event="false"
>
  ...
<toggle_variable/>
 */

export const ToggleVariable = ({variable, context = "global", on, off, prevent_default = "true", children, options, default_state = "off", use_event = "false"}) => {

  const dispatch = useDispatch();
  const varsContext = useSelector(state => state.app.variables)
  const [state, setState] = useState()

  useEffect(()=>{
    const newState = default_state === "on" ? "on" : "off";
    const finalData = getOnOff(on, off, newState, varsContext)
    setState(newState);
    if( varsContext ){
      dispatch(appActions.setVariable(variable, finalData, context));
    }
  }, [on, off, default_state]);


  const handleClick = (event) => {
    if(prevent_default === "true"){
      event.preventDefault()
    }
    const newState = state === "on" ? "off" : "on";
    const finalData = getOnOff(on, off, newState, varsContext)
    if( varsContext ){
      dispatch(appActions.setVariable(variable, finalData, context));
    }
    setState(newState);
  }
  return <div onClick={handleClick} {...processOptions(options)}>{children}</div>;

}

const getOnOff = (on, off, state, context) => {
  return dataEval(
    state === "on" 
      ? processOptions(on, on, on)
      : processOptions(off, off, off)
    , context
  );
}

const dataEval = (data, varsContext) => {
  if (typeof data !== "string") return data;
  const newData = data.startsWith("ev|") 
  ? safeEval(data.substring(3))
  : data;
  const finalData = typeof newData === "function"
    ? newData(varsContext, document)
    : newData;
  return finalData;
}