UNPKG

framework-entersol-web

Version:

Framework based on bootstrap 5

160 lines (149 loc) 5.81 kB
import React from "react"; import { NavLink, Link } from "react-router-dom"; import parseReact, { domToReact, attributesToProps } from "html-react-parser"; import deepMerge from "./functions/deep-merge"; import Icons from "./media/icons"; import COMPONENTS from "./components"; /** * Clase utilizada para generar contenido dinámico en React a partir de una estructura de datos JSON. * * @class JsonRender */ export default class JsonRender { /** * Opciones para el análisis del contenido HTML. * @type {Object} */ parseOpts = { replace: domNode => { let C7tReplace; switch (domNode.name) { case 'navlink': C7tReplace = NavLink; break; case 'a': if (!domNode.attribs.to && domNode.attribs.href) return; C7tReplace = Link; break; case 'icons': C7tReplace = Icons; domNode.attribs.inline = domNode.attribs.inline === 'false' ? false : true; break; case 'textarea': case 'input': domNode.defaultValue = domNode.value; domNode.defaultChecked = domNode.checked; delete domNode.value; delete domNode.checked; default: return; } Object.keys(domNode).forEach(k => { if (k.match(/^on[A-Z]/)) { domNode[k] = this.props[k]; } }); return <C7tReplace {...attributesToProps(domNode.attribs)} children={domToReact(domNode.children, this.parseOpts)} />; } } /** * Crea una instancia de JsonRender. * @param {Object} props - Las propiedades del componente. * @param {Object} mutations - Las mutaciones para las secciones. */ constructor(props, mutations) { this.props = props; this.mutations = mutations; this.sections = this.sections.bind(this); this.buildContent = this.buildContent.bind(this); } /** * Construye el contenido basado en la estructura de datos proporcionada. * @param {any} content - El contenido a construir. * @param {number} index - El índice del contenido. * @returns {React.Component|React.Fragment|boolean} - El componente construido. */ buildContent(content, index) { if (!content) return false; if (typeof content === 'number') { return content; } else if (typeof content === 'string') { return (<React.Fragment key={content.name || index}> {parseReact(content, this.parseOpts)} </React.Fragment>); } else if (React.isValidElement(content)) { try { content.key = content.name || index; } catch (error) { } return content; } else if (Array.isArray(content)) return content.map(this.buildContent); if (Array.isArray(content.name)) content.name = content.name.join('-'); if (typeof content === 'object' && typeof content.name !== 'string') return Object.keys(content) .map((name, i) => this.buildContent({ name, ...content[name] }, i)); return this.sections(content, index); } /** * Construye una sección basada en la información proporcionada. * @param {Object} sectionRaw - Los datos de la sección. * @param {number} i - El índice de la sección. * @returns {React.Component|boolean} - El componente de la sección construido. */ sections(sectionRaw, i) { if (typeof this.mutations === 'function') { const m = this.mutations(sectionRaw.name, sectionRaw) || {}; //Si la mutacion contiene elementos react, hacer un deepMerge truena con loop infinito Object.assign(sectionRaw, m); } if (typeof sectionRaw.active === 'boolean' && !sectionRaw.active) return false; const { component: componentName, content, placeholder, label, message, errorMessage, managerName, wrapperClasses, ...section } = sectionRaw; const { location, match, childrenIn = this.childrenIn, history, children } = this.props; const Component = COMPONENTS[componentName] || (COMPONENTS.Component); const componentProps = { ...section, managerName: managerName || this.props.name, label: this.buildContent(label), placeholder: this.buildContent(placeholder), message: this.buildContent(message), errorMessage: this.buildContent(errorMessage), location, match, history } if (Component.dontBuildContent) componentProps.content = content; if (!Component.dontBuildContent && content && (childrenIn === section.name)) { componentProps.children = <> {this.buildContent(content)} {children} </> } else if (!Component.dontBuildContent && content) { componentProps.children = this.buildContent(content); } else if (childrenIn === section.name) { componentProps.children = children; } const cnSection = [componentProps.name + '-section']; if (this.props.test) cnSection.push('test-section-wrapper'); if (this.props.wrapperClasses) cnSection.push(this.props.wrapperClasses); if (wrapperClasses) cnSection.push(wrapperClasses); const exclusionSec = ['NavLink', 'Image', 'Link', 'Icons', 'Action', 'DropdownButtonContainer', 'ModalButtonContainer', 'DropdownItem'] .includes(componentName); const Wrapper = componentProps.wrapper === false ? false : componentProps.wrapper || Component.wrapper || 'section'; if (!Wrapper || exclusionSec || componentProps.tag) { if (this.props.test) { if (!componentProps.style) componentProps.style = {}; componentProps.style.border = '1px solid yellow'; } return <Component key={componentProps.name || i} {...componentProps} /> } return (<Wrapper key={componentProps.name || i} className={cnSection.flat().join(' ')}> <Component {...componentProps} /> </Wrapper>); } }