page.mdx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. import { pageMetadata } from "@/lib/page-metadata";
  2. export const metadata = pageMetadata("docs/api/solid");
  3. # @json-render/solid
  4. SolidJS components, providers, and hooks for rendering json-render specs.
  5. ## Installation
  6. <PackageInstall packages="@json-render/core @json-render/solid" />
  7. Peer dependencies: `solid-js ^1.9.0` and `zod ^4.0.0`.
  8. <PackageInstall packages="solid-js zod" />
  9. ## Providers
  10. ### StateProvider
  11. ```tsx
  12. <StateProvider
  13. initialState={{}}
  14. onStateChange={(changes) => console.log(changes)}
  15. >
  16. {/* children */}
  17. </StateProvider>
  18. ```
  19. <table>
  20. <thead>
  21. <tr>
  22. <th>Prop</th>
  23. <th>Type</th>
  24. <th>Description</th>
  25. </tr>
  26. </thead>
  27. <tbody>
  28. <tr>
  29. <td>
  30. <code>store</code>
  31. </td>
  32. <td>
  33. <code>StateStore</code>
  34. </td>
  35. <td>
  36. External store (controlled mode). When provided,{" "}
  37. <code>initialState</code> and <code>onStateChange</code> are ignored.
  38. </td>
  39. </tr>
  40. <tr>
  41. <td>
  42. <code>initialState</code>
  43. </td>
  44. <td>
  45. <code>Record&lt;string, unknown&gt;</code>
  46. </td>
  47. <td>Initial state model for uncontrolled mode.</td>
  48. </tr>
  49. <tr>
  50. <td>
  51. <code>onStateChange</code>
  52. </td>
  53. <td>
  54. <code>
  55. {"(changes: Array<{ path: string; value: unknown }>) => void"}
  56. </code>
  57. </td>
  58. <td>Called for uncontrolled state updates.</td>
  59. </tr>
  60. </tbody>
  61. </table>
  62. ### ActionProvider
  63. ```tsx
  64. <ActionProvider
  65. handlers={{ submit: async (params) => {} }}
  66. navigate={(path) => {}}
  67. >
  68. {/* children */}
  69. </ActionProvider>
  70. ```
  71. ### VisibilityProvider
  72. ```tsx
  73. <VisibilityProvider>{/* children */}</VisibilityProvider>
  74. ```
  75. ### ValidationProvider
  76. ```tsx
  77. <ValidationProvider customFunctions={{ custom: (value) => Boolean(value) }}>
  78. {/* children */}
  79. </ValidationProvider>
  80. ```
  81. ### JSONUIProvider
  82. Combined provider wrapper for state, visibility, validation, and actions.
  83. ```tsx
  84. <JSONUIProvider
  85. registry={registry}
  86. initialState={{}}
  87. handlers={handlers}
  88. validationFunctions={validationFunctions}
  89. >
  90. <Renderer spec={spec} registry={registry} />
  91. </JSONUIProvider>
  92. ```
  93. ## defineRegistry
  94. Create a typed component registry and action helpers from a catalog.
  95. ```tsx
  96. const { registry, handlers, executeAction } = defineRegistry(catalog, {
  97. components: {
  98. Card: (renderProps) => <div>{renderProps.children}</div>,
  99. Button: (renderProps) => (
  100. <button onClick={() => renderProps.emit("press")}>
  101. {renderProps.element.props.label as string}
  102. </button>
  103. ),
  104. },
  105. actions: {
  106. submit: async (params, setState, state) => {
  107. // custom action logic
  108. },
  109. },
  110. });
  111. ```
  112. ## Components
  113. ### Renderer
  114. ```tsx
  115. <Renderer spec={spec} registry={registry} loading={false} />
  116. ```
  117. Renders a `Spec` tree using your registry.
  118. ### createRenderer
  119. Build an app-level renderer from catalog + components:
  120. ```tsx
  121. const AppRenderer = createRenderer(catalog, {
  122. Card: (renderProps) => <div>{renderProps.children}</div>,
  123. });
  124. <AppRenderer spec={spec} state={{}} onAction={(name, params) => {}} />;
  125. ```
  126. ## Hooks
  127. - `useStateStore()`
  128. - `useStateValue(path)` - returns an accessor
  129. - `useStateBinding(path)` - returns `[Accessor<T | undefined>, setValue]`
  130. - `useVisibility()` / `useIsVisible(condition)`
  131. - `useActions()` / `useAction(binding)`
  132. - `useValidation()` / `useOptionalValidation()`
  133. - `useFieldValidation(path, config)` - returns accessor-backed `state`, `errors`, and `isValid`
  134. - `useBoundProp(value, bindingPath)`
  135. - `useUIStream(options)`
  136. - `useChatUI(options)`
  137. ## Built-in Actions
  138. `ActionProvider` handles these built-in actions:
  139. - `setState`
  140. - `pushState`
  141. - `removeState`
  142. - `validateForm`
  143. ## Component Props
  144. Registry components receive:
  145. ```ts
  146. interface ComponentRenderProps<P = Record<string, unknown>> {
  147. element: UIElement<string, P>;
  148. children?: JSX.Element;
  149. emit: (event: string) => void;
  150. on: (event: string) => EventHandle;
  151. bindings?: Record<string, string>;
  152. loading?: boolean;
  153. }
  154. ```
  155. Use `emit("event")` to dispatch event bindings. Use `on("event")` to access `EventHandle` metadata (`bound`, `shouldPreventDefault`, `emit`).
  156. ## Reactivity Notes
  157. - Keep changing reads in JSX expressions, `createMemo`, or `createEffect`.
  158. - Avoid props destructuring in component signatures when you need live updates.
  159. - `StateProvider` and other contexts expose getter-backed values so consumers read live signals.
  160. - `useStateValue`, `useStateBinding`, and `useFieldValidation` expose reactive accessors; call them as functions.