renderer.tsx 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. "use client";
  2. import type { ReactNode } from "react";
  3. import { toast } from "sonner";
  4. import {
  5. Renderer,
  6. type Spec,
  7. StateProvider,
  8. VisibilityProvider,
  9. ActionProvider,
  10. } from "@json-render/react";
  11. import { registry, Fallback } from "./registry";
  12. // =============================================================================
  13. // PlaygroundRenderer
  14. // =============================================================================
  15. interface PlaygroundRendererProps {
  16. spec: Spec | null;
  17. data?: Record<string, unknown>;
  18. loading?: boolean;
  19. }
  20. const fallbackRenderer = (renderProps: { element: { type: string } }) => (
  21. <Fallback type={renderProps.element.type} />
  22. );
  23. /**
  24. * Action handlers for the playground preview.
  25. * These are passed to ActionProvider so custom actions (buttonClick, formSubmit,
  26. * linkClick) work when triggered from the rendered UI.
  27. */
  28. const actionHandlers: Record<
  29. string,
  30. (params: Record<string, unknown>) => void
  31. > = {
  32. buttonClick: (params) => {
  33. const message = (params?.message as string) || "Button clicked!";
  34. toast.success(message);
  35. },
  36. formSubmit: (params) => {
  37. const formName = (params?.formName as string) || "Form";
  38. toast.success(`${formName} submitted successfully!`);
  39. },
  40. linkClick: (params) => {
  41. const href = (params?.href as string) || "#";
  42. toast.info(`Navigating to: ${href}`);
  43. },
  44. };
  45. export function PlaygroundRenderer({
  46. spec,
  47. data,
  48. loading,
  49. }: PlaygroundRendererProps): ReactNode {
  50. if (!spec) return null;
  51. return (
  52. <StateProvider initialState={data ?? spec.state}>
  53. <VisibilityProvider>
  54. <ActionProvider handlers={actionHandlers}>
  55. <Renderer
  56. spec={spec}
  57. registry={registry}
  58. fallback={fallbackRenderer}
  59. loading={loading}
  60. />
  61. </ActionProvider>
  62. </VisibilityProvider>
  63. </StateProvider>
  64. );
  65. }