Source: templates/TagWithVariable.js

import React, { useEffect, useMemo } from "react";
import { useSelector } from "react-redux";
import { booleanString, emptyObject } from "../../_core";
const safeEval = require('safe-eval-2')
const objectPath = require("object-path");


/**
 * Componente wrapper que contiene a aquellos componentes que usan variables.
 * @name Reactor.Components.Templates.TagWithVariable
 * @param {string} propiedad La propiedad que va a actualizarse con una variable se debe llamar var-nombre_propiedad
 * @param {string} context Nombre del contexto que contiene o va a contener la variable, si se omite el contexto sera "global"
 * @class
 * @example
<input name="nombre_del_campo" var-value="nombre_variable" context="un_contexto" />
*/

export const TagWithVariable = ({tag: Tag = "div", variables = {}, context = "global", ...props}) => {

  const variablesState = useSelector(state => state.app.variables[context]) || emptyObject;
  
  const propsVariables = useMemo(() => 
    Object.keys(variables).reduce((prev, curr) => {
      const variable = variables[curr];
      try{
        const fnProp = props[`fn-${curr.substring(4)}`];
        const propValue = fnProp
        ? processData(fnProp, objectPath.get(variablesState, variable), variablesState, document) 
        : objectPath.get(variablesState, variable);
        return {
          ...prev, 
          [curr.substring(4)]: propValue
        }
      }catch(e){
        console.log(e)
        return {
          ...prev, [curr.substring(4)]: variable 
        }
      }
    }, {}) 
  , [context, variables, variablesState]);


  const newProps = useMemo(()=>({
    ...Object.keys(props).reduce((prev, curr)=>{
      const propName = curr === "context2" ? "context" : curr;
      return {
        ...prev, 
        [propName]: !curr.startsWith("fn-") && props[curr]
      }
    }, {}),
    ...propsVariables
  }), [props, propsVariables]);

  useEffect(()=>{
    booleanString(newProps?.debug) && console.log("TagWithVariables", {props: newProps});
  }, [newProps])

  return <Tag {...newProps} context={context}>{newProps.children}</Tag>;

}

const processData = (fn, value, ctx, doc) => {
  return safeEval(fn , {value, ctx, doc});
}