Skip to content

Instantly share code, notes, and snippets.

@SamuelChojnacki
Last active March 23, 2025 14:32
Show Gist options
  • Save SamuelChojnacki/9020fab53fa4acb11cb281507204d1a9 to your computer and use it in GitHub Desktop.
Save SamuelChojnacki/9020fab53fa4acb11cb281507204d1a9 to your computer and use it in GitHub Desktop.
generate react component from json
// render-json.tsx
import React from "react";
/**
* Interface pour un élément dans la structure JSON
*/
interface ElementJson {
/** Type d'élément HTML (div, p, span, etc.) */
type: string;
/** Attributs HTML et propriétés de l'élément */
attr?: Record<string, string | number | boolean>;
/** Contenu texte ou tableau d'éléments enfants */
content?: string | ElementJson[];
/** Enfants du composant (alternative à content) */
children?: ElementJson[];
/** Clé optionnelle pour les listes d'éléments */
key?: string;
}
/**
* Convertit un objet JSON en élément React compatible avec Tailwind CSS
* @param json Structure JSON du composant à rendre
* @returns Élément React généré
*/
export function renderJson(json: ElementJson): React.ReactNode {
const { type, attr = {}, content, children, key } = json;
// Convertir les attributs HTML en attributs React
const reactAttrs: Record<string, any> = { key };
// Traiter tous les attributs
const attrKeys = Object.keys(attr);
for (const attrName of attrKeys) {
const value = attr[attrName];
// Convertir class en className pour React
if (attrName === "class") {
reactAttrs.className = value;
}
// Convertir for en htmlFor pour React
else if (attrName === "for") {
reactAttrs.htmlFor = value;
}
// Traiter les événements spéciaux (onClick, onChange, etc.)
else if (attrName.startsWith("on") && typeof value === "string") {
// Ignorer pour l'instant - peut être implémenté avec des gestionnaires d'événements personnalisés
// dans une version plus avancée
}
// Tous les autres attributs passent directement
else {
reactAttrs[attrName] = value;
}
}
// Préparer les enfants à rendre
const childElements: React.ReactNode[] = [];
// Si content est une chaîne, c'est le contenu principal
if (typeof content === "string") {
childElements.push(content);
}
// Si content est un tableau, traiter récursivement
else if (Array.isArray(content)) {
for (let index = 0; index < content.length; index++) {
const item = content[index];
// Si c'est un élément JSON, le rendre récursivement
if (typeof item === "object" && item !== null) {
const itemWithKey = {
...item,
key: item.key || `content-${index}`,
};
childElements.push(renderJson(itemWithKey));
} else {
// Sinon c'est probablement une chaîne, l'ajouter directement
childElements.push(item);
}
}
}
// Traiter les enfants après le contenu principal
if (Array.isArray(children)) {
for (let index = 0; index < children.length; index++) {
const child = children[index];
// Ajouter une clé si elle n'existe pas
const childWithKey = {
...child,
key: child.key || `child-${index}`,
};
childElements.push(renderJson(childWithKey));
}
}
// Créer l'élément React avec ses attributs et enfants
return React.createElement(type, reactAttrs, ...childElements);
}
/**
* Composant React qui utilise renderJson pour convertir un JSON en élément React
*/
const JsonToElement: React.FC<{ json: ElementJson }> = ({ json }) => {
return <>{renderJson(json)}</>;
};
export default JsonToElement;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment