page.tsx 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. import Link from "next/link";
  2. import { Code } from "@/components/code";
  3. export const metadata = {
  4. title: "Validation | json-render",
  5. };
  6. export default function ValidationPage() {
  7. return (
  8. <article>
  9. <h1 className="text-3xl font-bold mb-4">Validation</h1>
  10. <p className="text-muted-foreground mb-8">
  11. Validate form inputs with built-in and custom functions.
  12. </p>
  13. <h2 className="text-xl font-semibold mt-12 mb-4">Built-in Validators</h2>
  14. <p className="text-sm text-muted-foreground mb-4">
  15. json-render includes common validation functions:
  16. </p>
  17. <ul className="list-disc list-inside text-sm text-muted-foreground space-y-1 mb-4">
  18. <li>
  19. <code className="text-foreground">required</code> — Value must be
  20. non-empty
  21. </li>
  22. <li>
  23. <code className="text-foreground">email</code> — Valid email format
  24. </li>
  25. <li>
  26. <code className="text-foreground">minLength</code> — Minimum string
  27. length
  28. </li>
  29. <li>
  30. <code className="text-foreground">maxLength</code> — Maximum string
  31. length
  32. </li>
  33. <li>
  34. <code className="text-foreground">pattern</code> — Match a regex
  35. pattern
  36. </li>
  37. <li>
  38. <code className="text-foreground">min</code> — Minimum numeric value
  39. </li>
  40. <li>
  41. <code className="text-foreground">max</code> — Maximum numeric value
  42. </li>
  43. </ul>
  44. <h2 className="text-xl font-semibold mt-12 mb-4">
  45. Using Validation in JSON
  46. </h2>
  47. <Code lang="json">{`{
  48. "type": "TextField",
  49. "props": {
  50. "label": "Email",
  51. "valuePath": "/form/email",
  52. "checks": [
  53. { "fn": "required", "message": "Email is required" },
  54. { "fn": "email", "message": "Invalid email format" }
  55. ],
  56. "validateOn": "blur"
  57. }
  58. }`}</Code>
  59. <h2 className="text-xl font-semibold mt-12 mb-4">
  60. Validation with Parameters
  61. </h2>
  62. <Code lang="json">{`{
  63. "type": "TextField",
  64. "props": {
  65. "label": "Password",
  66. "valuePath": "/form/password",
  67. "checks": [
  68. { "fn": "required", "message": "Password is required" },
  69. {
  70. "fn": "minLength",
  71. "args": { "length": 8 },
  72. "message": "Password must be at least 8 characters"
  73. },
  74. {
  75. "fn": "pattern",
  76. "args": { "pattern": "[A-Z]" },
  77. "message": "Must contain at least one uppercase letter"
  78. }
  79. ]
  80. }
  81. }`}</Code>
  82. <h2 className="text-xl font-semibold mt-12 mb-4">
  83. Custom Validation Functions
  84. </h2>
  85. <p className="text-sm text-muted-foreground mb-4">
  86. Define custom validators in your catalog:
  87. </p>
  88. <Code lang="typescript">{`import { defineCatalog } from '@json-render/core';
  89. import { schema } from '@json-render/react';
  90. import { z } from 'zod';
  91. const catalog = defineCatalog(schema, {
  92. components: { /* ... */ },
  93. functions: {
  94. isValidPhone: {
  95. description: 'Validates phone number format',
  96. },
  97. isUniqueEmail: {
  98. description: 'Checks if email is not already registered',
  99. },
  100. },
  101. });`}</Code>
  102. <p className="text-sm text-muted-foreground mb-4">
  103. Then implement them in your ValidationProvider:
  104. </p>
  105. <Code lang="tsx">{`import { ValidationProvider } from '@json-render/react';
  106. function App() {
  107. const customValidators = {
  108. isValidPhone: (value) => {
  109. const phoneRegex = /^\\+?[1-9]\\d{1,14}$/;
  110. return phoneRegex.test(value);
  111. },
  112. isUniqueEmail: async (value) => {
  113. const response = await fetch(\`/api/check-email?email=\${value}\`);
  114. const { available } = await response.json();
  115. return available;
  116. },
  117. };
  118. return (
  119. <ValidationProvider functions={customValidators}>
  120. {/* Your UI */}
  121. </ValidationProvider>
  122. );
  123. }`}</Code>
  124. <h2 className="text-xl font-semibold mt-12 mb-4">Using in Components</h2>
  125. <Code lang="tsx">{`import { useFieldValidation } from '@json-render/react';
  126. function TextField({ props }) {
  127. const { value, setValue, errors, validate } = useFieldValidation(
  128. props.valuePath,
  129. props.checks
  130. );
  131. return (
  132. <div>
  133. <label>{props.label}</label>
  134. <input
  135. value={value || ''}
  136. onChange={(e) => setValue(e.target.value)}
  137. onBlur={() => validate()}
  138. />
  139. {errors.map((error, i) => (
  140. <p key={i} className="text-red-500 text-sm">{error}</p>
  141. ))}
  142. </div>
  143. );
  144. }`}</Code>
  145. <h2 className="text-xl font-semibold mt-12 mb-4">Validation Timing</h2>
  146. <p className="text-sm text-muted-foreground mb-4">
  147. Control when validation runs with{" "}
  148. <code className="text-foreground">validateOn</code>:
  149. </p>
  150. <ul className="list-disc list-inside text-sm text-muted-foreground space-y-1">
  151. <li>
  152. <code className="text-foreground">change</code> — Validate on every
  153. input change
  154. </li>
  155. <li>
  156. <code className="text-foreground">blur</code> — Validate when field
  157. loses focus
  158. </li>
  159. <li>
  160. <code className="text-foreground">submit</code> — Validate only on
  161. form submission
  162. </li>
  163. </ul>
  164. <h2 className="text-xl font-semibold mt-12 mb-4">Next</h2>
  165. <p className="text-sm text-muted-foreground">
  166. Learn about{" "}
  167. <Link href="/docs/ai-sdk" className="text-foreground hover:underline">
  168. AI SDK integration
  169. </Link>
  170. .
  171. </p>
  172. </article>
  173. );
  174. }