@thorprovider/storefront 0.4.0-mvp.0 → 0.4.0-mvp.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/README.md +173 -153
  2. package/VENDOR.md +69 -0
  3. package/assets/openspec/config.yaml +38 -0
  4. package/assets/templates/AGENTS.md +76 -0
  5. package/assets/templates/app/app/[[...slug]]/page.tsx +42 -1
  6. package/assets/templates/app/app/[[...slug]]/renderer.tsx +13 -2
  7. package/assets/templates/app/app/globals.css +5 -8
  8. package/assets/templates/app/app/layout.tsx +1 -5
  9. package/assets/templates/app/app/robots.ts +9 -3
  10. package/assets/templates/app/app/sitemap.ts +64 -5
  11. package/assets/templates/app/lib/__STOREFRONT__/actions.ts +70 -0
  12. package/assets/templates/app/lib/__STOREFRONT__/catalog.ts +15 -5
  13. package/assets/templates/app/lib/__STOREFRONT__/commerce.ts +71 -0
  14. package/assets/templates/app/lib/__STOREFRONT__/composition.ts +26 -0
  15. package/assets/templates/app/lib/__STOREFRONT__/handlers.core.ts +36 -4
  16. package/assets/templates/app/lib/__STOREFRONT__/registry.tsx +82 -50
  17. package/assets/templates/app/lib/__STOREFRONT__/runtime.ts +3 -0
  18. package/assets/templates/app/lib/__STOREFRONT__/schema.ts +29 -14
  19. package/assets/templates/app/lib/__STOREFRONT__/section-observation.ts +182 -0
  20. package/assets/templates/app/lib/__STOREFRONT__/section-sources.ts +130 -0
  21. package/assets/templates/app/lib/__STOREFRONT__/shell/content.ts +31 -7
  22. package/assets/templates/app/lib/__STOREFRONT__/shell/props.ts +4 -0
  23. package/assets/templates/app/lib/__STOREFRONT__/spec/index.ts +56 -26
  24. package/assets/templates/app/lib/__STOREFRONT__/spec/seo.ts +165 -0
  25. package/assets/templates/app/lib/__STOREFRONT__/store-context.ts +26 -7
  26. package/assets/templates/app/lib/__STOREFRONT__/views/sections/index.ts +2 -1
  27. package/assets/templates/app/lib/__STOREFRONT__/views/sections/products.client.tsx +100 -0
  28. package/assets/templates/app/lib/__STOREFRONT__/views/sections/products.tsx +19 -0
  29. package/assets/templates/app/lib/__STOREFRONT__/views/sections/schema.products.ts +39 -0
  30. package/assets/templates/features/checkout/handlers.ts +6 -0
  31. package/assets/templates/features/customer-auth/state.ts +10 -1
  32. package/assets/templates/views/account/index.tsx +1 -1
  33. package/assets/templates/views/account/registry.tsx +80 -19
  34. package/assets/templates/views/account/schema.ts +1 -0
  35. package/assets/templates/views/cart/content.ts +11 -0
  36. package/assets/templates/views/cart/data.ts +23 -0
  37. package/assets/templates/views/cart/index.tsx +53 -0
  38. package/assets/templates/views/cart/props.ts +12 -0
  39. package/assets/templates/views/cart/registry.tsx +81 -0
  40. package/assets/templates/views/cart/schema.ts +52 -0
  41. package/assets/templates/views/category/assembly/assembly.json +1 -0
  42. package/assets/templates/views/category/assembly/index.skeleton.tsx +64 -6
  43. package/assets/templates/views/category/assembly/registry.skeleton.tsx +2 -1
  44. package/assets/templates/views/category/assembly/slots/breadcrumb/Breadcrumb/binding.json +5 -0
  45. package/assets/templates/views/category/assembly/slots/breadcrumb/Breadcrumb/catalog.part +4 -0
  46. package/assets/templates/views/category/assembly/slots/breadcrumb/Breadcrumb/element.part +7 -0
  47. package/assets/templates/views/category/assembly/slots/breadcrumb/Breadcrumb/registry.part +18 -0
  48. package/assets/templates/views/category/index.tsx +76 -7
  49. package/assets/templates/views/category/props.ts +7 -0
  50. package/assets/templates/views/category/registry.tsx +19 -0
  51. package/assets/templates/views/category/schema.ts +13 -0
  52. package/assets/templates/views/home/assembly/assembly.json +9 -0
  53. package/assets/templates/views/home/assembly/index.skeleton.tsx +22 -4
  54. package/assets/templates/views/home/assembly/slots/hero/StorefrontHero1/element.part +1 -1
  55. package/assets/templates/views/home/assembly/slots/hero/StorefrontHero1/registry.part +2 -2
  56. package/assets/templates/views/home/data.ts +9 -0
  57. package/assets/templates/views/home/index.tsx +23 -5
  58. package/assets/templates/views/home/registry.tsx +2 -2
  59. package/assets/templates/views/product/data.ts +4 -2
  60. package/assets/templates/views/product/index.tsx +49 -5
  61. package/assets/templates/views/product/props.ts +7 -0
  62. package/assets/templates/views/product/registry.tsx +25 -0
  63. package/assets/templates/views/product/schema.ts +13 -0
  64. package/assets/templates/views/static/content.ts +4 -4
  65. package/assets/templates/views/static/index.tsx +1 -1
  66. package/bin/storefront.js +1231 -154
  67. package/examples/merchandising/category-led.json +37 -0
  68. package/examples/merchandising/collection-led.json +37 -0
  69. package/package.json +11 -7
  70. package/recipes/archetypes.json +9 -22
  71. package/recipes/catalog.json +40 -1
  72. package/recipes/features.json +25 -2
  73. package/recipes/recipe.schema.json +1 -1
  74. package/recipes/recipes.json +32 -30
  75. package/recipes/sections.json +10 -0
  76. package/recipes/validate.mjs +54 -0
  77. package/scripts/candidate.mjs +4 -4
  78. package/scripts/composers.mjs +25 -5
  79. package/scripts/env-file.mjs +86 -0
  80. package/scripts/file-classes.mjs +5 -0
  81. package/scripts/migrate-english-routes.mjs +276 -0
  82. package/scripts/pinning.mjs +74 -5
  83. package/scripts/plan-apply.mjs +149 -5
  84. package/scripts/reconcile.mjs +49 -11
  85. package/scripts/render-templates.mjs +97 -44
  86. package/scripts/section-config.mjs +253 -0
  87. package/scripts/starter.mjs +17 -0
  88. package/scripts/theme/color.mjs +185 -0
  89. package/scripts/theme/css-theme.mjs +233 -0
  90. package/scripts/theme/fonts.mjs +123 -0
  91. package/scripts/theme/import-export.mjs +125 -0
  92. package/scripts/theme/preset.mjs +93 -0
  93. package/scripts/theme/theme-plan.mjs +292 -0
  94. package/scripts/theme/tokens.mjs +137 -0
  95. package/scripts/view-assembly.mjs +47 -1
  96. package/skills/sf-feature/SKILL.md +32 -19
  97. package/skills/sf-setup/SKILL.md +79 -0
  98. package/skills/sf-theme-gen/SKILL.md +99 -36
  99. package/skills/sf-theme-gen/references/shadcn-theming.md +87 -0
  100. package/skills/{shadcn-theming/references/templates → sf-theme-gen/references}/theme-setup.md +15 -19
  101. package/skills/{shadcn-theming → sf-theme-gen}/references/theming-guide.md +6 -11
  102. package/skills/sf-view-gen/SKILL.md +63 -40
  103. package/skills/sf-view-gen/assets/recipes/archetypes.json +9 -22
  104. package/skills/sf-view-gen/assets/recipes/catalog.json +40 -1
  105. package/skills/sf-view-gen/assets/recipes/features.json +25 -2
  106. package/skills/sf-view-gen/assets/recipes/recipes.json +32 -30
  107. package/skills/sf-view-gen/assets/recipes/sections.json +10 -0
  108. package/skills/sf-view-gen/assets/templates/views/sections/products.client.tsx +100 -0
  109. package/skills/sf-view-gen/assets/templates/views/sections/products.tsx +19 -0
  110. package/skills/sf-view-gen/assets/templates/views/sections/schema.products.ts +39 -0
  111. package/skills/{json-render-core/SKILL.md → sf-view-gen/references/json-render-core.md} +4 -27
  112. package/skills/{json-render-next/SKILL.md → sf-view-gen/references/json-render-next.md} +5 -8
  113. package/skills/{json-render-react/SKILL.md → sf-view-gen/references/json-render-react.md} +3 -5
  114. package/skills/{json-render-shadcn/SKILL.md → sf-view-gen/references/json-render-shadcn.md} +3 -5
  115. package/skills/sf-view-gen/references/views.md +28 -37
  116. package/skills/sf-view-gen/scripts/validate.mjs +54 -0
  117. package/skills/storefront-workflow/SKILL.md +94 -31
  118. package/skills/{storefront-best-practices/reference/design.md → storefront-workflow/references/design-consistency.md} +13 -29
  119. package/CHANGELOG.md +0 -84
  120. package/assets/templates/views/user-panel/index.tsx +0 -106
  121. package/assets/templates/views/user-panel/registry.tsx +0 -54
  122. package/assets/templates/views/user-panel/schema.ts +0 -79
  123. package/commands/sf-add-view.md +0 -57
  124. package/commands/sf-feature.md +0 -28
  125. package/commands/sf-theme.md +0 -26
  126. package/commands/sf-view.md +0 -67
  127. package/skills/building-storefronts/SKILL.md +0 -178
  128. package/skills/building-storefronts/references/frontend-integration.md +0 -229
  129. package/skills/json-render-remotion/SKILL.md +0 -111
  130. package/skills/json-render-solid/SKILL.md +0 -204
  131. package/skills/nextjs-shadcn/SKILL.md +0 -367
  132. package/skills/nextjs-shadcn/references/architecture.md +0 -499
  133. package/skills/nextjs-shadcn/references/project-setup.md +0 -162
  134. package/skills/nextjs-shadcn/references/shadcn-platform.md +0 -261
  135. package/skills/nextjs-shadcn/references/sidebar.md +0 -274
  136. package/skills/nextjs-shadcn/references/styling.md +0 -555
  137. package/skills/shadcn-component-discovery/SKILL.md +0 -273
  138. package/skills/shadcn-component-discovery/references/registries.md +0 -226
  139. package/skills/shadcn-theming/SKILL.md +0 -104
  140. package/skills/storefront-best-practices/SKILL.md +0 -421
  141. package/skills/storefront-best-practices/reference/components/breadcrumbs.md +0 -123
  142. package/skills/storefront-best-practices/reference/components/cart-popup.md +0 -189
  143. package/skills/storefront-best-practices/reference/components/country-selector.md +0 -298
  144. package/skills/storefront-best-practices/reference/components/footer.md +0 -112
  145. package/skills/storefront-best-practices/reference/components/hero.md +0 -241
  146. package/skills/storefront-best-practices/reference/components/megamenu.md +0 -239
  147. package/skills/storefront-best-practices/reference/components/navbar.md +0 -397
  148. package/skills/storefront-best-practices/reference/components/popups.md +0 -221
  149. package/skills/storefront-best-practices/reference/components/product-card.md +0 -125
  150. package/skills/storefront-best-practices/reference/components/product-reviews.md +0 -217
  151. package/skills/storefront-best-practices/reference/components/product-slider.md +0 -174
  152. package/skills/storefront-best-practices/reference/components/search.md +0 -101
  153. package/skills/storefront-best-practices/reference/connecting-to-backend.md +0 -391
  154. package/skills/storefront-best-practices/reference/features/promotions.md +0 -307
  155. package/skills/storefront-best-practices/reference/features/wishlist.md +0 -230
  156. package/skills/storefront-best-practices/reference/layouts/account.md +0 -380
  157. package/skills/storefront-best-practices/reference/layouts/cart.md +0 -316
  158. package/skills/storefront-best-practices/reference/layouts/checkout.md +0 -486
  159. package/skills/storefront-best-practices/reference/layouts/home-page.md +0 -264
  160. package/skills/storefront-best-practices/reference/layouts/order-confirmation.md +0 -231
  161. package/skills/storefront-best-practices/reference/layouts/product-details.md +0 -527
  162. package/skills/storefront-best-practices/reference/layouts/product-listing.md +0 -520
  163. package/skills/storefront-best-practices/reference/layouts/static-pages.md +0 -356
  164. package/skills/storefront-best-practices/reference/medusa.md +0 -307
  165. /package/skills/{storefront-best-practices/reference → storefront-workflow/references}/mobile-responsiveness.md +0 -0
  166. /package/skills/{storefront-best-practices/reference → storefront-workflow/references}/seo.md +0 -0
@@ -1,229 +0,0 @@
1
- # Frontend SDK Integration
2
-
3
- ## Contents
4
- - [Frontend SDK Pattern](#frontend-sdk-pattern)
5
- - [Locating the SDK](#locating-the-sdk)
6
- - [Using sdk.client.fetch()](#using-sdkclientfetch)
7
- - [React Query Pattern](#react-query-pattern)
8
- - [Query Key Best Practices](#query-key-best-practices)
9
- - [Error Handling](#error-handling)
10
- - [Optimistic Updates](#optimistic-updates)
11
-
12
- This guide covers how to integrate Medusa custom API routes with frontend applications using the Medusa SDK and React Query.
13
-
14
- **Note:** API routes are also referred to as "endpoints" - these terms are interchangeable.
15
-
16
- ## Frontend SDK Pattern
17
-
18
- ### Locating the SDK
19
-
20
- **IMPORTANT:** Never hardcode SDK import paths. Always locate where the SDK is instantiated in the project first.
21
-
22
- Look for `@medusajs/js-sdk`
23
-
24
- The SDK instance is typically exported as `sdk`:
25
-
26
- ```typescript
27
- import { sdk } from "[LOCATE IN PROJECT]"
28
- ```
29
-
30
- ### Using sdk.client.fetch()
31
-
32
- **⚠️ CRITICAL: ALWAYS use the Medusa JS SDK for ALL API requests - NEVER use regular fetch()**
33
-
34
- **Why this is critical:**
35
- - **Store API routes** require the publishable API key in headers
36
- - **Admin API routes** require authentication headers
37
- - **Regular fetch()** without these headers will cause errors
38
- - The SDK automatically handles all required headers for you
39
-
40
- **When to use what:**
41
- - **Existing endpoints** (built-in Medusa routes): Use existing SDK methods like `sdk.store.product.list()`, `sdk.admin.order.retrieve()`
42
- - **Custom endpoints** (your custom API routes): Use `sdk.client.fetch()` for custom routes
43
-
44
- **⚠️ CRITICAL: The SDK handles JSON serialization automatically. NEVER use JSON.stringify() on the body.**
45
-
46
- Call custom API routes using the SDK:
47
-
48
- ```typescript
49
- import { sdk } from "[LOCATE SDK INSTANCE IN PROJECT]"
50
-
51
- // ✅ CORRECT - Pass object directly
52
- const result = await sdk.client.fetch("/store/my-route", {
53
- method: "POST",
54
- body: {
55
- email: "user@example.com",
56
- name: "John Doe",
57
- },
58
- })
59
-
60
- // ❌ WRONG - Don't use JSON.stringify
61
- const result = await sdk.client.fetch("/store/my-route", {
62
- method: "POST",
63
- body: JSON.stringify({ // ❌ DON'T DO THIS!
64
- email: "user@example.com",
65
- }),
66
- })
67
- ```
68
-
69
- **Key points:**
70
-
71
- - **The SDK handles JSON serialization automatically** - just pass plain objects
72
- - **NEVER use JSON.stringify()** - this will break the request
73
- - No need to set Content-Type headers - SDK adds them
74
- - Session/JWT authentication is handled automatically
75
- - Publishable API key is automatically added
76
-
77
- ### Built-in Endpoints vs Custom Endpoints
78
-
79
- **⚠️ CRITICAL: Use the appropriate SDK method based on endpoint type**
80
-
81
- ```typescript
82
- import { sdk } from "[LOCATE SDK INSTANCE IN PROJECT]"
83
-
84
- // ✅ CORRECT - Built-in endpoint: Use existing SDK method
85
- const products = await sdk.store.product.list({
86
- limit: 10,
87
- offset: 0
88
- })
89
-
90
- // ✅ CORRECT - Custom endpoint: Use sdk.client.fetch()
91
- const reviews = await sdk.client.fetch("/store/products/prod_123/reviews")
92
-
93
- // ❌ WRONG - Using regular fetch for ANY endpoint
94
- const products = await fetch("http://localhost:9000/store/products")
95
- // ❌ Error: Missing publishable API key header!
96
-
97
- // ❌ WRONG - Using regular fetch for custom endpoint
98
- const reviews = await fetch("http://localhost:9000/store/products/prod_123/reviews")
99
- // ❌ Error: Missing publishable API key header!
100
-
101
- // ❌ WRONG - Using sdk.client.fetch() for built-in endpoint when SDK method exists
102
- const products = await sdk.client.fetch("/store/products")
103
- // ❌ Less type-safe than using sdk.store.product.list()
104
- ```
105
-
106
- **Why this matters:**
107
- - **Store routes** require `x-publishable-api-key` header - SDK adds it automatically
108
- - **Admin routes** require `Authorization` and session cookie headers - SDK adds them automatically
109
- - **Regular fetch()** doesn't include these headers → API returns authentication/authorization errors
110
- - Using existing SDK methods provides **better type safety** and autocomplete
111
-
112
- ## React Query Pattern
113
-
114
- Use `useQuery` for GET requests and `useMutation` for POST/DELETE:
115
-
116
- ```typescript
117
- import { sdk } from "[LOCATE SDK INSTANCE IN PROJECT]"
118
- import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"
119
-
120
- function MyComponent({ userId }: { userId: string }) {
121
- const queryClient = useQueryClient()
122
-
123
- // GET request - fetching data
124
- const { data, isLoading } = useQuery({
125
- queryKey: ["my-data", userId],
126
- queryFn: () => sdk.client.fetch(`/store/my-route?userId=${userId}`),
127
- enabled: !!userId,
128
- })
129
-
130
- // POST request - mutation with cache invalidation
131
- const mutation = useMutation({
132
- mutationFn: (input: { email: string }) =>
133
- sdk.client.fetch("/store/my-route", { method: "POST", body: input }),
134
- onSuccess: () => {
135
- // Invalidate and refetch related queries
136
- queryClient.invalidateQueries({ queryKey: ["my-data"] })
137
- },
138
- })
139
-
140
- if (isLoading) return <p>Loading...</p>
141
-
142
- return (
143
- <div>
144
- <p>{data?.title}</p>
145
- <button
146
- onClick={() => mutation.mutate({ email: "test@example.com" })}
147
- disabled={mutation.isPending}
148
- >
149
- {mutation.isPending ? "Loading..." : "Submit"}
150
- </button>
151
- {mutation.isError && <p>Error occurred</p>}
152
- </div>
153
- )
154
- }
155
- ```
156
-
157
- **Key states:** `isLoading`, `isPending`, `isSuccess`, `isError`, `error`
158
-
159
- ## Query Key Best Practices
160
-
161
- Structure query keys for effective cache management:
162
-
163
- ```typescript
164
- // Good: Hierarchical structure
165
- queryKey: ["products", productId]
166
- queryKey: ["products", "list", { page, filters }]
167
-
168
- // Invalidate all product queries
169
- queryClient.invalidateQueries({ queryKey: ["products"] })
170
-
171
- // Invalidate specific product
172
- queryClient.invalidateQueries({ queryKey: ["products", productId] })
173
- ```
174
-
175
- ## Error Handling
176
-
177
- Handle API errors gracefully:
178
-
179
- ```typescript
180
- const mutation = useMutation({
181
- mutationFn: (input) => sdk.client.fetch("/store/my-route", {
182
- method: "POST",
183
- body: input
184
- }),
185
- onError: (error) => {
186
- console.error("Mutation failed:", error)
187
- // Show error message to user
188
- },
189
- })
190
-
191
- // In component
192
- {mutation.isError && (
193
- <p className="error">
194
- {mutation.error?.message || "An error occurred"}
195
- </p>
196
- )}
197
- ```
198
-
199
- ## Optimistic Updates
200
-
201
- Update UI immediately before server confirms:
202
-
203
- ```typescript
204
- const mutation = useMutation({
205
- mutationFn: (newItem) =>
206
- sdk.client.fetch("/store/items", { method: "POST", body: newItem }),
207
- onMutate: async (newItem) => {
208
- // Cancel outgoing refetches
209
- await queryClient.cancelQueries({ queryKey: ["items"] })
210
-
211
- // Snapshot previous value
212
- const previousItems = queryClient.getQueryData(["items"])
213
-
214
- // Optimistically update
215
- queryClient.setQueryData(["items"], (old) => [...old, newItem])
216
-
217
- // Return context with snapshot
218
- return { previousItems }
219
- },
220
- onError: (err, newItem, context) => {
221
- // Rollback on error
222
- queryClient.setQueryData(["items"], context.previousItems)
223
- },
224
- onSettled: () => {
225
- // Refetch after mutation
226
- queryClient.invalidateQueries({ queryKey: ["items"] })
227
- },
228
- })
229
- ```
@@ -1,111 +0,0 @@
1
- ---
2
- name: remotion
3
- description: Remotion renderer for json-render that turns JSON timeline specs into videos. Use when working with @json-render/remotion, building video compositions from JSON, creating video catalogs, or rendering AI-generated video timelines.
4
- ---
5
-
6
- # @json-render/remotion
7
-
8
- Remotion renderer that converts JSON timeline specs into video compositions.
9
-
10
- ## Quick Start
11
-
12
- ```typescript
13
- import { Player } from "@remotion/player";
14
- import { Renderer, type TimelineSpec } from "@json-render/remotion";
15
-
16
- function VideoPlayer({ spec }: { spec: TimelineSpec }) {
17
- return (
18
- <Player
19
- component={Renderer}
20
- inputProps={{ spec }}
21
- durationInFrames={spec.composition.durationInFrames}
22
- fps={spec.composition.fps}
23
- compositionWidth={spec.composition.width}
24
- compositionHeight={spec.composition.height}
25
- controls
26
- />
27
- );
28
- }
29
- ```
30
-
31
- ## Using Standard Components
32
-
33
- ```typescript
34
- import { defineCatalog } from "@json-render/core";
35
- import {
36
- schema,
37
- standardComponentDefinitions,
38
- standardTransitionDefinitions,
39
- standardEffectDefinitions,
40
- } from "@json-render/remotion";
41
-
42
- export const videoCatalog = defineCatalog(schema, {
43
- components: standardComponentDefinitions,
44
- transitions: standardTransitionDefinitions,
45
- effects: standardEffectDefinitions,
46
- });
47
- ```
48
-
49
- ## Adding Custom Components
50
-
51
- ```typescript
52
- import { z } from "zod";
53
-
54
- const catalog = defineCatalog(schema, {
55
- components: {
56
- ...standardComponentDefinitions,
57
- MyCustomClip: {
58
- props: z.object({ text: z.string() }),
59
- type: "scene",
60
- defaultDuration: 90,
61
- description: "My custom video clip",
62
- },
63
- },
64
- });
65
-
66
- // Pass custom component to Renderer
67
- <Player
68
- component={Renderer}
69
- inputProps={{
70
- spec,
71
- components: { MyCustomClip: MyCustomComponent },
72
- }}
73
- />
74
- ```
75
-
76
- ## Timeline Spec Structure
77
-
78
- ```json
79
- {
80
- "composition": { "id": "video", "fps": 30, "width": 1920, "height": 1080, "durationInFrames": 300 },
81
- "tracks": [{ "id": "main", "name": "Main", "type": "video", "enabled": true }],
82
- "clips": [
83
- { "id": "clip-1", "trackId": "main", "component": "TitleCard", "props": { "title": "Hello" }, "from": 0, "durationInFrames": 90 }
84
- ],
85
- "audio": { "tracks": [] }
86
- }
87
- ```
88
-
89
- ## Standard Components
90
-
91
- | Component | Type | Description |
92
- |-----------|------|-------------|
93
- | `TitleCard` | scene | Full-screen title with subtitle |
94
- | `TypingText` | scene | Terminal-style typing animation |
95
- | `ImageSlide` | image | Full-screen image display |
96
- | `SplitScreen` | scene | Two-panel comparison |
97
- | `QuoteCard` | scene | Quote with attribution |
98
- | `StatCard` | scene | Animated statistic display |
99
- | `TextOverlay` | overlay | Text overlay |
100
- | `LowerThird` | overlay | Name/title overlay |
101
-
102
- ## Key Exports
103
-
104
- | Export | Purpose |
105
- |--------|---------|
106
- | `Renderer` | Render spec to Remotion composition |
107
- | `schema` | Timeline schema |
108
- | `standardComponents` | Pre-built component registry |
109
- | `standardComponentDefinitions` | Catalog definitions |
110
- | `useTransition` | Transition animation hook |
111
- | `ClipWrapper` | Wrap clips with transitions |
@@ -1,204 +0,0 @@
1
- ---
2
- name: solid
3
- description: SolidJS renderer for json-render. Use when building @json-render/solid catalogs/registries, wiring Renderer providers, implementing bindings/actions, or troubleshooting Solid-specific reactivity patterns.
4
- ---
5
-
6
- # @json-render/solid
7
-
8
- `@json-render/solid` renders json-render specs into Solid component trees with fine-grained reactivity.
9
-
10
- ## Quick Start
11
-
12
- ```tsx
13
- import { Renderer, JSONUIProvider } from "@json-render/solid";
14
- import type { Spec } from "@json-render/solid";
15
- import { registry } from "./registry";
16
-
17
- export function App(props: { spec: Spec | null }) {
18
- return (
19
- <JSONUIProvider registry={registry} initialState={{}}>
20
- <Renderer spec={props.spec} registry={registry} />
21
- </JSONUIProvider>
22
- );
23
- }
24
- ```
25
-
26
- ## Create a Catalog
27
-
28
- ```typescript
29
- import { defineCatalog } from "@json-render/core";
30
- import { schema } from "@json-render/solid/schema";
31
- import { z } from "zod";
32
-
33
- export const catalog = defineCatalog(schema, {
34
- components: {
35
- Button: {
36
- props: z.object({
37
- label: z.string(),
38
- variant: z.enum(["primary", "secondary"]).nullable(),
39
- }),
40
- description: "Clickable button",
41
- },
42
- Card: {
43
- props: z.object({ title: z.string() }),
44
- description: "Card container",
45
- },
46
- },
47
- actions: {
48
- submit: { description: "Submit data" },
49
- },
50
- });
51
- ```
52
-
53
- ## Define Components
54
-
55
- Components receive `ComponentRenderProps` from the renderer:
56
-
57
- ```ts
58
- interface ComponentRenderProps<P = Record<string, unknown>> {
59
- element: UIElement<string, P>;
60
- children?: JSX.Element;
61
- emit: (event: string) => void;
62
- on: (event: string) => EventHandle;
63
- bindings?: Record<string, string>;
64
- loading?: boolean;
65
- }
66
- ```
67
-
68
- Example:
69
-
70
- ```tsx
71
- import type { BaseComponentProps } from "@json-render/solid";
72
-
73
- export function Button(props: BaseComponentProps<{ label: string }>) {
74
- return (
75
- <button onClick={() => props.emit("press")}>{props.props.label}</button>
76
- );
77
- }
78
- ```
79
-
80
- ## Create a Registry
81
-
82
- ```typescript
83
- import { defineRegistry } from "@json-render/solid";
84
- import { catalog } from "./catalog";
85
- import { Card } from "./Card";
86
- import { Button } from "./Button";
87
-
88
- const { registry, handlers, executeAction } = defineRegistry(catalog, {
89
- components: {
90
- Card,
91
- Button,
92
- },
93
- actions: {
94
- submit: async (params, setState, state) => {
95
- // custom action logic
96
- },
97
- },
98
- });
99
- ```
100
-
101
- ## Spec Structure
102
-
103
- ```json
104
- {
105
- "root": "card1",
106
- "elements": {
107
- "card1": {
108
- "type": "Card",
109
- "props": { "title": "Hello" },
110
- "children": ["btn1"]
111
- },
112
- "btn1": {
113
- "type": "Button",
114
- "props": { "label": "Click me" },
115
- "on": {
116
- "press": { "action": "submit" }
117
- }
118
- }
119
- }
120
- }
121
- ```
122
-
123
- ## Providers
124
-
125
- - `StateProvider`: state model read/write and controlled mode via `store`
126
- - `VisibilityProvider`: evaluates `visible` conditions
127
- - `ValidationProvider`: field validation + `validateForm` integration
128
- - `ActionProvider`: runs built-in and custom actions
129
- - `JSONUIProvider`: combined provider wrapper
130
-
131
- ## Hooks
132
-
133
- - `useStateStore`, `useStateValue`, `useStateBinding`
134
- - `useVisibility`, `useIsVisible`
135
- - `useActions`, `useAction`
136
- - `useValidation`, `useOptionalValidation`, `useFieldValidation`
137
- - `useBoundProp`
138
- - `useUIStream`, `useChatUI`
139
-
140
- ## Built-in Actions
141
-
142
- Handled automatically by `ActionProvider`:
143
-
144
- - `setState`
145
- - `pushState`
146
- - `removeState`
147
- - `validateForm`
148
-
149
- ## Dynamic Props and Bindings
150
-
151
- Nested lists can set `repeat.statePath` to `{ "$item": "field" }` inside an enclosing repeat.
152
-
153
- Supported expression forms include:
154
-
155
- - `{"$state": "/path"}`
156
- - `{"$bindState": "/path"}`
157
- - `{"$bindItem": "field"}`
158
- - `{"$template": "Hi ${/user/name}"}`
159
- - `{"$computed": "fn", "args": {...}}`
160
- - `{"$cond": <condition>, "$then": <value>, "$else": <value>}`
161
-
162
- Use `useBoundProp` in components for writable bound values:
163
-
164
- ```tsx
165
- import { useBoundProp } from "@json-render/solid";
166
-
167
- function Input(props: BaseComponentProps<{ value?: string }>) {
168
- const [value, setValue] = useBoundProp(
169
- props.props.value,
170
- props.bindings?.value,
171
- );
172
- return (
173
- <input
174
- value={String(value() ?? "")}
175
- onInput={(e) => setValue(e.currentTarget.value)}
176
- />
177
- );
178
- }
179
- ```
180
-
181
- `useStateValue`, `useStateBinding`, and the `state` / `errors` / `isValid` fields from `useFieldValidation` are reactive accessors in Solid. Call them as functions inside JSX, `createMemo`, or `createEffect`.
182
-
183
- ## Solid Reactivity Rules
184
-
185
- - Do not destructure component props in function signatures when values need to stay reactive.
186
- - Keep changing reads inside JSX expressions, `createMemo`, or `createEffect`.
187
- - Context values are exposed through getter-based objects so consumers always observe live signals.
188
-
189
- ## Streaming UI
190
-
191
- ```tsx
192
- import { useUIStream, Renderer } from "@json-render/solid";
193
-
194
- const stream = useUIStream({ api: "/api/generate-ui" });
195
- await stream.send("Create a support dashboard");
196
-
197
- <Renderer
198
- spec={stream.spec}
199
- registry={registry}
200
- loading={stream.isStreaming}
201
- />;
202
- ```
203
-
204
- Use `useChatUI` for chat + UI generation flows.