import { useState, useEffect, useMemo, useRef } from "react"; import { Renderer, StateProvider, ActionProvider, VisibilityProvider } from "@json-render/react"; import type { Spec } from "@json-render/core"; import { registry, handlers } from "./registry"; import { useHighlight } from "./useHighlight"; const SPECS = ["simple", "full"] as const; type SetState = (fn: (prev: Record) => Record) => void; function SpecRenderer({ spec }: { spec: Spec }) { const [state, setState] = useState>(spec.state ?? {}); const stateRef = useRef(state); const setStateRef = useRef(setState); stateRef.current = state; setStateRef.current = setState; const actionHandlers = useMemo( () => handlers(() => setStateRef.current, () => stateRef.current), [], ); return ( ); } function CodeBlock({ html, fallback, maxHeight = "40vh" }: { html: string; fallback: string; maxHeight?: string }) { if (html) { return (
); } return (
      {fallback}
    
); } export function App() { const [activeSpec, setActiveSpec] = useState(null); const [spec, setSpec] = useState(null); const [specJson, setSpecJson] = useState(""); const [jsxSource, setJsxSource] = useState(""); const [loading, setLoading] = useState(false); const jsxHtml = useHighlight(jsxSource, "tsx"); const jsonHtml = useHighlight(specJson, "json"); useEffect(() => { if (!activeSpec) return; setLoading(true); Promise.all([ fetch(`/api/spec/${activeSpec}`).then((r) => r.json()), fetch(`/api/source/${activeSpec}`).then((r) => r.text()), ]) .then(([data, source]) => { setSpec(data); setSpecJson(JSON.stringify(data, null, 2)); setJsxSource(source); }) .finally(() => setLoading(false)); }, [activeSpec]); if (!activeSpec) { return (

jfx examples

JSX → json-render Spec. Pick a spec to see the live UI and JSON output.

{SPECS.map((name) => ( ))}
); } return (

{activeSpec} spec

{loading ? (

Loading...

) : ( spec && (

Live UI

JSX Source

JSON Output

) )}
); }