page.tsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import Link from "next/link";
  2. import { Code } from "@/components/code";
  3. export const metadata = {
  4. title: "Actions | json-render",
  5. };
  6. export default function ActionsPage() {
  7. return (
  8. <article>
  9. <h1 className="text-3xl font-bold mb-4">Actions</h1>
  10. <p className="text-muted-foreground mb-8">
  11. Handle user interactions safely with named actions.
  12. </p>
  13. <h2 className="text-xl font-semibold mt-12 mb-4">Why Named Actions?</h2>
  14. <p className="text-sm text-muted-foreground mb-4">
  15. Instead of AI generating arbitrary code, it declares <em>intent</em> by
  16. name. Your application provides the implementation. This is a core
  17. guardrail.
  18. </p>
  19. <h2 className="text-xl font-semibold mt-12 mb-4">Defining Actions</h2>
  20. <p className="text-sm text-muted-foreground mb-4">
  21. Define available actions in your catalog:
  22. </p>
  23. <Code lang="typescript">{`const catalog = createCatalog({
  24. components: { /* ... */ },
  25. actions: {
  26. submit_form: {
  27. params: z.object({
  28. formId: z.string(),
  29. }),
  30. description: 'Submit a form',
  31. },
  32. export_data: {
  33. params: z.object({
  34. format: z.enum(['csv', 'pdf', 'json']),
  35. filters: z.object({
  36. dateRange: z.string().optional(),
  37. }).optional(),
  38. }),
  39. },
  40. navigate: {
  41. params: z.object({
  42. url: z.string(),
  43. }),
  44. },
  45. },
  46. });`}</Code>
  47. <h2 className="text-xl font-semibold mt-12 mb-4">ActionProvider</h2>
  48. <p className="text-sm text-muted-foreground mb-4">
  49. Provide action handlers to your app:
  50. </p>
  51. <Code lang="tsx">{`import { ActionProvider } from '@json-render/react';
  52. function App() {
  53. const handlers = {
  54. submit_form: async (params) => {
  55. const response = await fetch('/api/submit', {
  56. method: 'POST',
  57. body: JSON.stringify({ formId: params.formId }),
  58. });
  59. return response.json();
  60. },
  61. export_data: async (params) => {
  62. const blob = await generateExport(params.format, params.filters);
  63. downloadBlob(blob, \`export.\${params.format}\`);
  64. },
  65. navigate: (params) => {
  66. window.location.href = params.url;
  67. },
  68. };
  69. return (
  70. <ActionProvider handlers={handlers}>
  71. {/* Your UI */}
  72. </ActionProvider>
  73. );
  74. }`}</Code>
  75. <h2 className="text-xl font-semibold mt-12 mb-4">
  76. Using Actions in Components
  77. </h2>
  78. <Code lang="tsx">{`const Button = ({ element, onAction }) => (
  79. <button onClick={() => onAction(element.props.action, {})}>
  80. {element.props.label}
  81. </button>
  82. );
  83. // Or use the useAction hook
  84. import { useAction } from '@json-render/react';
  85. function SubmitButton() {
  86. const submitForm = useAction('submit_form');
  87. return (
  88. <button onClick={() => submitForm({ formId: 'contact' })}>
  89. Submit
  90. </button>
  91. );
  92. }`}</Code>
  93. <h2 className="text-xl font-semibold mt-12 mb-4">
  94. Actions with Confirmation
  95. </h2>
  96. <p className="text-sm text-muted-foreground mb-4">
  97. AI can declare actions that require user confirmation:
  98. </p>
  99. <Code lang="json">{`{
  100. "type": "Button",
  101. "props": {
  102. "label": "Delete Account",
  103. "action": {
  104. "name": "delete_account",
  105. "params": { "userId": "123" },
  106. "confirm": {
  107. "title": "Delete Account?",
  108. "message": "This action cannot be undone.",
  109. "variant": "danger"
  110. }
  111. }
  112. }
  113. }`}</Code>
  114. <h2 className="text-xl font-semibold mt-12 mb-4">Action Callbacks</h2>
  115. <p className="text-sm text-muted-foreground mb-4">
  116. Handle success and error states:
  117. </p>
  118. <Code lang="json">{`{
  119. "type": "Button",
  120. "props": {
  121. "label": "Save",
  122. "action": {
  123. "name": "save_changes",
  124. "params": { "documentId": "doc-1" },
  125. "onSuccess": {
  126. "set": { "/ui/savedMessage": "Changes saved!" }
  127. },
  128. "onError": {
  129. "set": { "/ui/errorMessage": "$error.message" }
  130. }
  131. }
  132. }
  133. }`}</Code>
  134. <h2 className="text-xl font-semibold mt-12 mb-4">Next</h2>
  135. <p className="text-sm text-muted-foreground">
  136. Learn about{" "}
  137. <Link
  138. href="/docs/visibility"
  139. className="text-foreground hover:underline"
  140. >
  141. conditional visibility
  142. </Link>
  143. .
  144. </p>
  145. </article>
  146. );
  147. }