create-questpie 2.0.4 → 2.1.0

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 (152) hide show
  1. package/dist/index.mjs +362 -119
  2. package/package.json +2 -3
  3. package/templates/elysia/AGENTS.md +56 -0
  4. package/templates/elysia/CLAUDE.md +39 -0
  5. package/templates/elysia/Dockerfile +24 -0
  6. package/templates/elysia/README.md +148 -0
  7. package/templates/elysia/docker/init-extensions.sql +11 -0
  8. package/templates/elysia/docker-compose.yml +21 -0
  9. package/templates/elysia/env.example +16 -0
  10. package/templates/elysia/gitignore +6 -0
  11. package/templates/elysia/package.json +47 -0
  12. package/templates/elysia/questpie.config.ts +12 -0
  13. package/templates/elysia/src/index.ts +21 -0
  14. package/templates/elysia/src/lib/auth-client.ts +32 -0
  15. package/templates/elysia/src/lib/client.ts +13 -0
  16. package/templates/elysia/src/lib/env.ts +24 -0
  17. package/templates/elysia/src/lib/query-client.ts +18 -0
  18. package/templates/elysia/src/lib/query.ts +18 -0
  19. package/templates/elysia/src/questpie/server/.generated/context.gen.ts +200 -0
  20. package/templates/elysia/src/questpie/server/.generated/entities.gen.ts +84 -0
  21. package/templates/elysia/src/questpie/server/.generated/factories.ts +65 -0
  22. package/templates/elysia/src/questpie/server/.generated/index.ts +131 -0
  23. package/templates/elysia/src/questpie/server/.generated/names.gen.ts +25 -0
  24. package/templates/elysia/src/questpie/server/app.ts +10 -0
  25. package/templates/elysia/src/questpie/server/collections/index.ts +1 -0
  26. package/templates/elysia/src/questpie/server/collections/posts.collection.ts +10 -0
  27. package/templates/elysia/src/questpie/server/config/auth.ts +8 -0
  28. package/templates/elysia/src/questpie/server/config/openapi.ts +10 -0
  29. package/templates/elysia/src/questpie/server/globals/index.ts +1 -0
  30. package/templates/elysia/src/questpie/server/globals/site-settings.global.ts +10 -0
  31. package/templates/elysia/src/questpie/server/modules.ts +8 -0
  32. package/templates/elysia/src/questpie/server/questpie.config.ts +21 -0
  33. package/templates/elysia/tsconfig.json +28 -0
  34. package/templates/hono/AGENTS.md +56 -0
  35. package/templates/hono/CLAUDE.md +39 -0
  36. package/templates/hono/Dockerfile +24 -0
  37. package/templates/hono/README.md +148 -0
  38. package/templates/hono/docker/init-extensions.sql +11 -0
  39. package/templates/hono/docker-compose.yml +21 -0
  40. package/templates/hono/env.example +16 -0
  41. package/templates/hono/gitignore +6 -0
  42. package/templates/hono/package.json +47 -0
  43. package/templates/hono/questpie.config.ts +12 -0
  44. package/templates/hono/src/index.ts +30 -0
  45. package/templates/hono/src/lib/auth-client.ts +32 -0
  46. package/templates/hono/src/lib/client.ts +13 -0
  47. package/templates/hono/src/lib/env.ts +24 -0
  48. package/templates/hono/src/lib/query-client.ts +18 -0
  49. package/templates/hono/src/lib/query.ts +18 -0
  50. package/templates/hono/src/questpie/server/.generated/context.gen.ts +200 -0
  51. package/templates/hono/src/questpie/server/.generated/entities.gen.ts +84 -0
  52. package/templates/hono/src/questpie/server/.generated/factories.ts +65 -0
  53. package/templates/hono/src/questpie/server/.generated/index.ts +131 -0
  54. package/templates/hono/src/questpie/server/.generated/names.gen.ts +25 -0
  55. package/templates/hono/src/questpie/server/app.ts +10 -0
  56. package/templates/hono/src/questpie/server/collections/index.ts +1 -0
  57. package/templates/hono/src/questpie/server/collections/posts.collection.ts +10 -0
  58. package/templates/hono/src/questpie/server/config/auth.ts +8 -0
  59. package/templates/hono/src/questpie/server/config/openapi.ts +10 -0
  60. package/templates/hono/src/questpie/server/globals/index.ts +1 -0
  61. package/templates/hono/src/questpie/server/globals/site-settings.global.ts +10 -0
  62. package/templates/hono/src/questpie/server/modules.ts +8 -0
  63. package/templates/hono/src/questpie/server/questpie.config.ts +21 -0
  64. package/templates/hono/tsconfig.json +28 -0
  65. package/templates/next/AGENTS.md +55 -0
  66. package/templates/next/CLAUDE.md +39 -0
  67. package/templates/next/Dockerfile +25 -0
  68. package/templates/next/README.md +148 -0
  69. package/templates/next/components.json +22 -0
  70. package/templates/next/docker/init-extensions.sql +11 -0
  71. package/templates/next/docker-compose.yml +21 -0
  72. package/templates/next/env.example +16 -0
  73. package/templates/next/gitignore +10 -0
  74. package/templates/next/next-env.d.ts +5 -0
  75. package/templates/next/next.config.ts +20 -0
  76. package/templates/next/package.json +54 -0
  77. package/templates/next/postcss.config.mjs +8 -0
  78. package/templates/next/public/.gitkeep +0 -0
  79. package/templates/next/questpie.config.ts +12 -0
  80. package/templates/next/src/app/admin/[[...all]]/page.tsx +34 -0
  81. package/templates/next/src/app/admin/admin.css +4 -0
  82. package/templates/next/src/app/admin/layout.tsx +63 -0
  83. package/templates/next/src/app/api/[...all]/route.ts +24 -0
  84. package/templates/next/src/app/layout.tsx +24 -0
  85. package/templates/next/src/app/not-found.tsx +18 -0
  86. package/templates/next/src/app/page.tsx +74 -0
  87. package/templates/next/src/app/providers.tsx +11 -0
  88. package/templates/next/src/lib/auth-client.ts +12 -0
  89. package/templates/next/src/lib/client.ts +13 -0
  90. package/templates/next/src/lib/env.ts +24 -0
  91. package/templates/next/src/lib/query-client.ts +18 -0
  92. package/templates/next/src/lib/query.ts +18 -0
  93. package/templates/next/src/questpie/admin/.generated/client.ts +13 -0
  94. package/templates/next/src/questpie/admin/admin.ts +9 -0
  95. package/templates/next/src/questpie/admin/modules.ts +3 -0
  96. package/templates/next/src/questpie/server/.generated/context.gen.ts +204 -0
  97. package/templates/next/src/questpie/server/.generated/entities.gen.ts +100 -0
  98. package/templates/next/src/questpie/server/.generated/factories.ts +204 -0
  99. package/templates/next/src/questpie/server/.generated/index.ts +139 -0
  100. package/templates/next/src/questpie/server/.generated/names.gen.ts +31 -0
  101. package/templates/next/src/questpie/server/app.ts +10 -0
  102. package/templates/next/src/questpie/server/collections/index.ts +1 -0
  103. package/templates/next/src/questpie/server/collections/posts.collection.ts +58 -0
  104. package/templates/next/src/questpie/server/config/admin.ts +80 -0
  105. package/templates/next/src/questpie/server/config/auth.ts +8 -0
  106. package/templates/next/src/questpie/server/config/openapi.ts +10 -0
  107. package/templates/next/src/questpie/server/globals/index.ts +1 -0
  108. package/templates/next/src/questpie/server/globals/site-settings.global.ts +19 -0
  109. package/templates/next/src/questpie/server/modules.ts +9 -0
  110. package/templates/next/src/questpie/server/questpie.config.ts +21 -0
  111. package/templates/next/src/styles.css +125 -0
  112. package/templates/next/tsconfig.json +37 -0
  113. package/templates/tanstack-start/AGENTS.md +35 -607
  114. package/templates/tanstack-start/CLAUDE.md +26 -134
  115. package/templates/tanstack-start/README.md +13 -1
  116. package/templates/tanstack-start/docker/init-extensions.sql +11 -0
  117. package/templates/tanstack-start/docker-compose.yml +1 -0
  118. package/templates/tanstack-start/src/lib/auth-client.ts +1 -1
  119. package/templates/tanstack-start/src/lib/client.ts +1 -1
  120. package/templates/tanstack-start/src/lib/query.ts +18 -0
  121. package/templates/tanstack-start/src/questpie/server/collections/index.ts +1 -1
  122. package/templates/tanstack-start/src/questpie/server/globals/index.ts +1 -1
  123. package/templates/tanstack-start/src/questpie/server/questpie.config.ts +1 -1
  124. package/templates/tanstack-start/src/routes/__root.tsx +31 -1
  125. package/templates/tanstack-start/src/routes/api/$.ts +1 -1
  126. package/templates/tanstack-start/src/routes/index.tsx +97 -0
  127. package/skills/questpie/AGENTS.md +0 -2871
  128. package/skills/questpie/SKILL.md +0 -293
  129. package/skills/questpie/coverage.json +0 -213
  130. package/skills/questpie/references/auth.md +0 -236
  131. package/skills/questpie/references/business-logic.md +0 -620
  132. package/skills/questpie/references/codegen-plugin-api.md +0 -382
  133. package/skills/questpie/references/crud-api.md +0 -580
  134. package/skills/questpie/references/data-modeling.md +0 -509
  135. package/skills/questpie/references/extend.md +0 -584
  136. package/skills/questpie/references/field-types.md +0 -398
  137. package/skills/questpie/references/infrastructure-adapters.md +0 -720
  138. package/skills/questpie/references/mcp.md +0 -147
  139. package/skills/questpie/references/multi-tenancy.md +0 -363
  140. package/skills/questpie/references/production.md +0 -640
  141. package/skills/questpie/references/query-operators.md +0 -125
  142. package/skills/questpie/references/quickstart.md +0 -562
  143. package/skills/questpie/references/rules.md +0 -454
  144. package/skills/questpie/references/sandbox.md +0 -110
  145. package/skills/questpie/references/tanstack-query.md +0 -543
  146. package/skills/questpie/references/type-inference.md +0 -167
  147. package/skills/questpie/references/workflows.md +0 -155
  148. package/skills/questpie-admin/AGENTS.md +0 -1515
  149. package/skills/questpie-admin/SKILL.md +0 -443
  150. package/skills/questpie-admin/references/blocks.md +0 -331
  151. package/skills/questpie-admin/references/custom-ui.md +0 -305
  152. package/skills/questpie-admin/references/views.md +0 -449
@@ -1,449 +0,0 @@
1
- ---
2
- name: questpie-admin/views
3
- description: QUESTPIE admin views list-view table form-view sections sidebar dashboard widgets filters bulk-actions visibility history versioning sorting search
4
- ---
5
-
6
- # QUESTPIE Admin Views
7
-
8
- This skill builds on questpie-admin.
9
-
10
- Views control how data appears in the QUESTPIE admin panel. They are configured **server-side** on collections and globals, then rendered by the admin client via registries.
11
-
12
- ```text
13
- Server Config Admin UI
14
- .list(({ v }) => v.collectionTable({})) -> Table with columns, sort, search
15
- .form(({ v, f }) => v.collectionForm({})) -> Form with sections, sidebar, tabs
16
- sidebar({...}) -> Navigation sidebar
17
- dashboard({...}) -> Dashboard with widgets
18
- ```
19
-
20
- ## List Views
21
-
22
- Configure table views with `.list()` on a collection.
23
-
24
- ### Basic Table
25
-
26
- ```ts
27
- .list(({ v }) => v.collectionTable({}))
28
- ```
29
-
30
- Shows all fields as columns with default rendering.
31
-
32
- ### Custom Columns and Search
33
-
34
- ```ts
35
- .list(({ v, f }) =>
36
- v.collectionTable({
37
- columns: [f.name, f.email, f.isActive, f.createdAt],
38
- searchableFields: [f.name, f.email],
39
- defaultSort: { field: f.createdAt, direction: "desc" },
40
- }),
41
- )
42
- ```
43
-
44
- | Option | Type | Description |
45
- | ------------------ | ---------------------- | ------------------------------ |
46
- | `columns` | `Field[]` | Fields to show as columns |
47
- | `searchableFields` | `Field[]` | Fields included in text search |
48
- | `defaultSort` | `{ field, direction }` | Default sort order |
49
-
50
- ## Form Views
51
-
52
- Configure edit forms with `.form()`.
53
-
54
- ### Basic Form
55
-
56
- ```ts
57
- .form(({ v, f }) => v.collectionForm({}))
58
- ```
59
-
60
- Renders all fields in a single column.
61
-
62
- ### Sections
63
-
64
- Group fields into labeled sections with optional grid layout:
65
-
66
- ```ts
67
- .form(({ v, f }) =>
68
- v.collectionForm({
69
- fields: [
70
- {
71
- type: "section",
72
- label: { en: "Contact Information" },
73
- layout: "grid",
74
- columns: 2,
75
- fields: [f.name, f.email, f.phone],
76
- },
77
- {
78
- type: "section",
79
- label: { en: "Profile" },
80
- fields: [f.bio],
81
- },
82
- ],
83
- }),
84
- )
85
- ```
86
-
87
- | Option | Type | Description |
88
- | ------------- | ------------------- | ------------------------------------ |
89
- | `type` | `"section"` | Required |
90
- | `label` | `string \| i18n` | Section heading |
91
- | `description` | `string \| i18n` | Section description |
92
- | `layout` | `"grid" \| "stack"` | Field layout |
93
- | `columns` | `number` | Grid columns (with `layout: "grid"`) |
94
- | `fields` | `Field[]` | Fields in this section |
95
-
96
- ### Form Sidebar
97
-
98
- Place fields in a right sidebar panel:
99
-
100
- ```ts
101
- .form(({ v, f }) =>
102
- v.collectionForm({
103
- sidebar: {
104
- position: "right",
105
- fields: [f.isActive, f.avatar, f.status],
106
- },
107
- fields: [ /* main content sections */ ],
108
- }),
109
- )
110
- ```
111
-
112
- ### Computed Fields
113
-
114
- Auto-compute values from other fields:
115
-
116
- ```ts
117
- {
118
- field: f.slug,
119
- compute: {
120
- handler: ({ data }) => {
121
- if (data.name && !data.slug?.trim()) {
122
- return slugify(data.name);
123
- }
124
- return undefined;
125
- },
126
- deps: ({ data }) => [data.name, data.slug],
127
- debounce: 300,
128
- },
129
- }
130
- ```
131
-
132
- | Option | Type | Description |
133
- | ---------- | ---------------- | ------------------------ |
134
- | `handler` | `(ctx) => value` | Compute function |
135
- | `deps` | `(ctx) => any[]` | Reactive dependencies |
136
- | `debounce` | `number` | Debounce in milliseconds |
137
-
138
- ### Conditional Visibility
139
-
140
- Show or hide fields based on other field values:
141
-
142
- ```ts
143
- {
144
- field: f.cancellationReason,
145
- hidden: ({ data }) => data.status !== "cancelled",
146
- }
147
- ```
148
-
149
- Read-only fields:
150
-
151
- ```ts
152
- {
153
- field: f.customerName,
154
- readOnly: ({ data }) => !!data.customer,
155
- }
156
- ```
157
-
158
- Section-level visibility:
159
-
160
- ```ts
161
- {
162
- type: "section",
163
- label: { en: "SEO" },
164
- hidden: ({ data }) => !data.showSeo,
165
- fields: [f.metaTitle, f.metaDescription],
166
- }
167
- ```
168
-
169
- ## Dashboard
170
-
171
- Configure in `config/admin.ts` under the `dashboard` key:
172
-
173
- ```ts title="config/admin.ts"
174
- import { adminConfig } from "#questpie/factories";
175
-
176
- export default adminConfig({
177
- dashboard: {
178
- title: { en: "Dashboard" },
179
- description: { en: "Overview of your app" },
180
- columns: 4,
181
- actions: [
182
- {
183
- id: "new-post",
184
- href: "/admin/collections/posts?create=true",
185
- label: { en: "New Post" },
186
- icon: { type: "icon", props: { name: "ph:plus" } },
187
- variant: "primary",
188
- },
189
- ],
190
- sections: [
191
- { id: "today", label: { en: "Today" }, layout: "grid", columns: 4 },
192
- { id: "business", label: { en: "Business" }, layout: "grid", columns: 4 },
193
- ],
194
- items: [
195
- /* widget items — see widget types below */
196
- ],
197
- },
198
- });
199
- ```
200
-
201
- ### Widget Types
202
-
203
- **Stats** — count records with optional filter:
204
-
205
- ```ts
206
- {
207
- sectionId: "today",
208
- id: "pending",
209
- type: "stats",
210
- collection: "appointments",
211
- label: { en: "Pending" },
212
- filter: { status: "pending" },
213
- span: 1,
214
- }
215
- ```
216
-
217
- **Value** — custom-loaded value with trend:
218
-
219
- ```ts
220
- {
221
- sectionId: "business",
222
- id: "revenue",
223
- type: "value",
224
- span: 2,
225
- refreshInterval: 1000 * 60 * 5,
226
- loader: async ({ app }) => ({
227
- value: 42000,
228
- formatted: "42,000 EUR",
229
- label: { en: "Monthly Revenue" },
230
- trend: { value: "+12%" },
231
- }),
232
- }
233
- ```
234
-
235
- **Progress** — progress bar toward a goal:
236
-
237
- ```ts
238
- {
239
- sectionId: "business",
240
- id: "goal",
241
- type: "progress",
242
- span: 1,
243
- showPercentage: true,
244
- label: { en: "Monthly Goal" },
245
- loader: async ({ app }) => ({ current: 350, target: 500 }),
246
- }
247
- ```
248
-
249
- **Chart** — chart from field values:
250
-
251
- ```ts
252
- {
253
- sectionId: "business",
254
- id: "by-status",
255
- type: "chart",
256
- collection: "appointments",
257
- field: "status",
258
- chartType: "pie",
259
- label: { en: "By Status" },
260
- span: 1,
261
- }
262
- ```
263
-
264
- **Recent Items** — list recent records:
265
-
266
- ```ts
267
- {
268
- sectionId: "ops",
269
- id: "recent",
270
- type: "recentItems",
271
- collection: "appointments",
272
- label: { en: "Recent" },
273
- limit: 6,
274
- dateField: "scheduledAt",
275
- span: 2,
276
- }
277
- ```
278
-
279
- **Timeline** — activity stream:
280
-
281
- ```ts
282
- {
283
- sectionId: "ops",
284
- id: "activity",
285
- type: "timeline",
286
- label: { en: "Activity" },
287
- maxItems: 8,
288
- showTimestamps: true,
289
- timestampFormat: "relative",
290
- loader: async ({ app }) => {
291
- const res = await app.collections.appointments.find({
292
- limit: 8,
293
- orderBy: { updatedAt: "desc" },
294
- });
295
- return res.docs.map((apt) => ({
296
- id: apt.id,
297
- title: apt.displayTitle,
298
- description: `Status: ${apt.status}`,
299
- timestamp: apt.updatedAt,
300
- variant: apt.status === "completed" ? "success" : "warning",
301
- href: `/admin/collections/appointments/${apt.id}`,
302
- }));
303
- },
304
- span: 2,
305
- }
306
- ```
307
-
308
- ## Sidebar
309
-
310
- Configure in `config/admin.ts` under the `sidebar` key:
311
-
312
- ```ts title="config/admin.ts"
313
- import { adminConfig } from "#questpie/factories";
314
-
315
- export default adminConfig({
316
- sidebar: {
317
- sections: [
318
- { id: "overview", title: { en: "Overview" } },
319
- { id: "content", title: { en: "Content" } },
320
- { id: "external", title: { en: "External" } },
321
- ],
322
- items: [
323
- {
324
- sectionId: "overview",
325
- type: "link",
326
- label: { en: "Dashboard" },
327
- href: "/admin",
328
- icon: { type: "icon", props: { name: "ph:house" } },
329
- },
330
- { sectionId: "overview", type: "global", global: "siteSettings" },
331
- { sectionId: "content", type: "collection", collection: "posts" },
332
- {
333
- sectionId: "external",
334
- type: "link",
335
- label: { en: "Open Website" },
336
- href: "/",
337
- external: true,
338
- icon: { type: "icon", props: { name: "ph:arrow-square-out" } },
339
- },
340
- ],
341
- },
342
- });
343
- ```
344
-
345
- Items appear in definition order within their section.
346
-
347
- Modules contribute sidebar items automatically. `adminModule` adds "Administration" with user management. `auditModule` adds an audit log item.
348
-
349
- ## Filters & Saved Views
350
-
351
- Filters are auto-generated from field definitions:
352
-
353
- | Field Type | Filter Operators |
354
- | ------------------- | ---------------------------------------- |
355
- | `text` | Contains, equals, starts with, ends with |
356
- | `number` | Equals, greater than, less than, between |
357
- | `boolean` | Is true, is false |
358
- | `select` | Is, is not, in |
359
- | `date` / `datetime` | Before, after, between |
360
- | `relation` | Is (picker) |
361
-
362
- Users can save filter + sort + column combinations as named views.
363
-
364
- ## Bulk Actions
365
-
366
- List views support multi-select. Check rows, then use the floating toolbar. Built-in: **Delete** (with confirmation). Soft-delete collections soft-delete instead of permanent removal.
367
-
368
- ## History & Versions
369
-
370
- Click the clock icon in the form toolbar. Two tabs:
371
-
372
- | Tab | Shows | Requires |
373
- | ------------ | ---------------------------------------------- | ----------------------------- |
374
- | **Activity** | Audit log (create, update, delete, transition) | `auditModule` |
375
- | **Versions** | Full document snapshots with restore | `.versioning()` on collection |
376
-
377
- Enable versioning:
378
-
379
- ```ts
380
- export const pages = collection("pages")
381
- .fields(({ f }) => ({ ... }))
382
- .options({ versioning: true });
383
- ```
384
-
385
- Disable audit for a specific collection:
386
-
387
- ```ts
388
- export const logs = collection("logs")
389
- .admin(() => ({ audit: false }))
390
- .fields(({ f }) => ({ ... }));
391
- ```
392
-
393
- ## Common Mistakes
394
-
395
- 1. **HIGH: Defining columns that don't match field names** — `columns: [f.name]` requires a `name` field in the collection's `.fields()`. Mismatches cause empty columns.
396
-
397
- 2. **MEDIUM: Not specifying `searchableFields`** — table search bar won't work unless you explicitly list which fields to search.
398
-
399
- 3. **MEDIUM: Forgetting sidebar section ordering** — items appear in definition order. If you want "Dashboard" at the top, define it first in the `items` array.
400
-
401
- 4. **MEDIUM: Missing `sectionId` on sidebar items** — every item must reference an existing section ID.
402
-
403
- 5. **LOW: Not setting `defaultSort`** — records appear in database insertion order which is usually not what users expect.
404
-
405
- ## Form Views and Live Preview
406
-
407
- Form views connect to the existing Live Preview system when the collection has `.preview()` configured. Keep `v.collectionForm()` as the form surface; do not introduce a separate visual-edit form API, a second default form view, or parallel preview API names. The form editor remains the source of patches, refreshes, commits, and resyncs.
408
-
409
- ### Enabling Preview on a Collection
410
-
411
- Add `.preview()` to the collection definition:
412
-
413
- ```ts
414
- export const pages = collection("pages")
415
- .fields(({ f }) => ({
416
- title: f.text().required().localized(),
417
- slug: f.text().required(),
418
- content: f.blocks().localized(),
419
- }))
420
- .preview({
421
- enabled: true,
422
- position: "right",
423
- defaultWidth: 50,
424
- url: ({ record }) => `/${record.slug}?preview=true`,
425
- });
426
- ```
427
-
428
- ### How It Works
429
-
430
- 1. The form view detects `.preview()` config and opens a split-screen layout
431
- 2. The preview iframe mirrors form state with snapshot, patch, refresh, commit, and resync messages
432
- 3. Save/autosave/Cmd+S/history/workflow/locks/actions stay in the form lifecycle
433
- 4. The preview page uses `useCollectionPreview({ initialData, onRefresh })`
434
- 5. `PreviewProvider`, `PreviewField`, and `BlockRenderer` wire field and block annotations
435
-
436
- ### Frontend Preparation Checklist
437
-
438
- Use this checklist before expecting visual editing to work:
439
-
440
- 1. The collection has `.preview({ url })`.
441
- 2. The page loader returns the complete rendered record shape.
442
- 3. Public workflow reads use `stage: "published"`; if public client/HTTP access is enabled, anonymous read access also requires `input?.stage === "published"`. Preview/draft-mode reads load the working record for authorized editors.
443
- 4. The page renderer calls `useCollectionPreview({ initialData, onRefresh })`.
444
- 5. The rendered page is wrapped in `PreviewProvider preview={preview}`.
445
- 6. UI reads from `preview.data`, not directly from loader data.
446
- 7. Scalar text uses `PreviewField field="..." editable="text" | "textarea"` when inline editing is expected.
447
- 8. Blocks render through `BlockRenderer` with `selectedBlockId` and `onBlockClick`.
448
- 9. `BlockScopeProvider` is only needed for custom/manual block rendering outside `BlockRenderer`.
449
- 10. Add/remove/reorder/nesting block operations stay in the existing block editor.