page.mdx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. import { pageMetadata } from "@/lib/page-metadata"
  2. export const metadata = pageMetadata("docs/devtools")
  3. # Devtools
  4. A drop-in inspector panel for any json-render app. See the spec tree, edit state inline, watch dispatched actions, follow stream patches live, browse your catalog, and pick DOM elements to map them back to spec keys.
  5. Production-safe: the component tree-shakes to a null render when `NODE_ENV === "production"`.
  6. ## Install
  7. Pick the adapter that matches your renderer.
  8. ### React
  9. ```bash
  10. npm install @json-render/devtools @json-render/devtools-react
  11. ```
  12. ### Vue
  13. ```bash
  14. npm install @json-render/devtools @json-render/devtools-vue
  15. ```
  16. ### Svelte
  17. ```bash
  18. npm install @json-render/devtools @json-render/devtools-svelte
  19. ```
  20. ### Solid
  21. ```bash
  22. npm install @json-render/devtools @json-render/devtools-solid
  23. ```
  24. ## Quick Start
  25. Drop `<JsonRenderDevtools />` anywhere inside your existing `<JSONUIProvider>` (or the equivalent provider tree).
  26. ```tsx
  27. // React
  28. import { JsonRenderDevtools } from "@json-render/devtools-react";
  29. <JSONUIProvider registry={registry} handlers={handlers}>
  30. <Renderer spec={spec} registry={registry} />
  31. <JsonRenderDevtools spec={spec} catalog={catalog} />
  32. </JSONUIProvider>
  33. ```
  34. That's it. A floating toggle appears in the bottom-right corner. Click it, or press <kbd>Ctrl</kbd>/<kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>J</kbd>, to open the drawer.
  35. ### Chat apps (AI SDK)
  36. When you're using `@ai-sdk/react`'s `useChat`, pass the `messages` prop so the Stream tab captures spec patches as they arrive:
  37. ```tsx
  38. <JsonRenderDevtools
  39. spec={spec}
  40. catalog={catalog}
  41. messages={messages}
  42. />
  43. ```
  44. ## Panels
  45. <table>
  46. <thead>
  47. <tr><th>Tab</th><th>What it shows</th></tr>
  48. </thead>
  49. <tbody>
  50. <tr>
  51. <td><strong>Spec</strong></td>
  52. <td>Element tree rooted at <code>spec.root</code>. Expand to walk children. Selecting an element fills a detail pane with its full props, visibility condition, event bindings, watchers, and any issues reported by <code>validateSpec</code>.</td>
  53. </tr>
  54. <tr>
  55. <td><strong>State</strong></td>
  56. <td>Every leaf path in the state model listed via <code>flattenToPointers</code>. Click a value to edit inline — writes go through <code>store.set</code>, so conditional elements and computed props re-evaluate immediately.</td>
  57. </tr>
  58. <tr>
  59. <td><strong>Actions</strong></td>
  60. <td>Timeline of dispatched actions: name, params, result or error, duration. Newest first. Expand a row for the full JSON payload.</td>
  61. </tr>
  62. <tr>
  63. <td><strong>Stream</strong></td>
  64. <td>Patches, text chunks, token usage, and lifecycle markers from the AI generation stream. Grouped by generation.</td>
  65. </tr>
  66. <tr>
  67. <td><strong>Catalog</strong></td>
  68. <td>Components and actions declared in your catalog with prop chips and type hints.</td>
  69. </tr>
  70. <tr>
  71. <td><strong>Pick</strong></td>
  72. <td>Click any element in the page to surface its entry in the Spec tab. Works because the renderer transparently tags each element with <code>data-jr-key</code> while devtools is mounted.</td>
  73. </tr>
  74. </tbody>
  75. </table>
  76. ## Props
  77. <table>
  78. <thead>
  79. <tr><th>Prop</th><th>Type</th><th>Default</th><th>Description</th></tr>
  80. </thead>
  81. <tbody>
  82. <tr>
  83. <td><code>spec</code></td>
  84. <td><code>Spec | null</code></td>
  85. <td><code>null</code></td>
  86. <td>The spec currently being rendered.</td>
  87. </tr>
  88. <tr>
  89. <td><code>catalog</code></td>
  90. <td><code>Catalog | null</code></td>
  91. <td><code>null</code></td>
  92. <td>Catalog definition — required for the Catalog panel.</td>
  93. </tr>
  94. <tr>
  95. <td><code>messages</code></td>
  96. <td><code>UIMessage[]</code></td>
  97. <td><code>undefined</code></td>
  98. <td>AI SDK <code>useChat</code> messages. Scanned for spec data parts and streamed into the Stream panel.</td>
  99. </tr>
  100. <tr>
  101. <td><code>initialOpen</code></td>
  102. <td><code>boolean</code></td>
  103. <td><code>false</code></td>
  104. <td>Start the drawer open.</td>
  105. </tr>
  106. <tr>
  107. <td><code>position</code></td>
  108. <td><code>"bottom-right" | "bottom-left" | "right"</code></td>
  109. <td><code>"bottom-right"</code></td>
  110. <td>Floating toggle button position.</td>
  111. </tr>
  112. <tr>
  113. <td><code>hotkey</code></td>
  114. <td><code>string | false</code></td>
  115. <td><code>"mod+shift+j"</code></td>
  116. <td>Keyboard shortcut. Use <code>mod</code> for Cmd on macOS / Ctrl elsewhere. Pass <code>false</code> to disable.</td>
  117. </tr>
  118. <tr>
  119. <td><code>bufferSize</code></td>
  120. <td><code>number</code></td>
  121. <td><code>500</code></td>
  122. <td>Max events retained in the ring buffer.</td>
  123. </tr>
  124. <tr>
  125. <td><code>onEvent</code></td>
  126. <td><code>(evt: DevtoolsEvent) =&gt; void</code></td>
  127. <td><code>undefined</code></td>
  128. <td>Optional tap — fires for every event as it is recorded. Useful for forwarding to analytics.</td>
  129. </tr>
  130. </tbody>
  131. </table>
  132. ## Production Safety
  133. The component renders `null` when `process.env.NODE_ENV === "production"`. Bundlers fold the constant check so the panel's code tree-shakes out of production builds.
  134. If you want extra certainty, gate the import behind an env check:
  135. ```tsx
  136. import dynamic from "next/dynamic";
  137. const JsonRenderDevtools = dynamic(
  138. () =>
  139. import("@json-render/devtools-react").then((m) => ({
  140. default: m.JsonRenderDevtools,
  141. })),
  142. { ssr: false, loading: () => null },
  143. );
  144. ```
  145. ## Advanced
  146. ### Imperative controls
  147. Use `useJsonRenderDevtools()` (React adapter only) to open / close the panel or record custom events from anywhere in the app:
  148. ```tsx
  149. import { useJsonRenderDevtools } from "@json-render/devtools-react";
  150. function DebugButton() {
  151. const devtools = useJsonRenderDevtools();
  152. return (
  153. <button onClick={() => devtools?.toggle()}>Toggle devtools</button>
  154. );
  155. }
  156. ```
  157. ### Server-side stream tap
  158. Capture stream events before they reach the client. Useful for server logs:
  159. ```ts
  160. import { tapJsonRenderStream } from "@json-render/devtools";
  161. const tapped = tapJsonRenderStream(
  162. result.toUIMessageStream(),
  163. serverEventStore,
  164. );
  165. writer.merge(pipeJsonRender(tapped));
  166. ```
  167. The `@json-render/devtools` core package exports `tapJsonRenderStream` and `tapYamlStream` for this pattern.