@amplifyup/sdk 0.1.63 → 0.1.65
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.
- package/README.md +133 -88
- package/dist/AmplifyRenderer.d.mts +40 -4
- package/dist/AmplifyRenderer.d.ts +40 -4
- package/dist/AmplifyRenderer.js +198 -67
- package/dist/AmplifyRenderer.js.map +1 -1
- package/dist/AmplifyRenderer.mjs +199 -68
- package/dist/AmplifyRenderer.mjs.map +1 -1
- package/dist/index.d.mts +8 -3
- package/dist/index.d.ts +8 -3
- package/dist/index.js +146 -28
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +146 -28
- package/dist/index.mjs.map +1 -1
- package/dist/{query-3AXnQgzO.d.ts → query-BLjZYjHJ.d.ts} +4 -3
- package/dist/{query-DIZjc7st.d.mts → query-DuRilU_n.d.mts} +4 -3
- package/dist/react.d.mts +19 -30
- package/dist/react.d.ts +19 -30
- package/dist/react.js +353 -311
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +350 -312
- package/dist/react.mjs.map +1 -1
- package/dist/server.d.mts +3 -3
- package/dist/server.d.ts +3 -3
- package/dist/server.js +146 -28
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +146 -28
- package/dist/server.mjs.map +1 -1
- package/dist/{types-Db_eLrfU.d.mts → types-C32MgOiv.d.mts} +96 -1
- package/dist/{types-Db_eLrfU.d.ts → types-C32MgOiv.d.ts} +96 -1
- package/package.json +1 -1
- package/dist/AmplifyRenderer-Bwob7ICJ.d.ts +0 -93
- package/dist/AmplifyRenderer-TawbUIKZ.d.mts +0 -93
package/README.md
CHANGED
|
@@ -97,12 +97,27 @@ fields.hero.image
|
|
|
97
97
|
|
|
98
98
|
fields.subheading // empty on a new page
|
|
99
99
|
// → { value: null, name: 'subheading' }
|
|
100
|
+
|
|
101
|
+
fields.posts.value[0].title // a row inside a list
|
|
102
|
+
// → { value: 'Ship faster', name: 'title', ref: { providerId, entity, id } }
|
|
100
103
|
```
|
|
101
104
|
|
|
102
105
|
`name` is the field's dot path. It is what lets `<Field>` know which field it is bound to without you telling it. `value` is the content, typed from your schema.
|
|
103
106
|
|
|
104
107
|
**The shape is identical on the live site, in a draft, and in Composer.** There is no mode where you get a bare string instead of an envelope, and no mode where an empty field is `undefined` instead of `{ value: null, name }`.
|
|
105
108
|
|
|
109
|
+
### Write targets
|
|
110
|
+
|
|
111
|
+
One rule explains everything about editing:
|
|
112
|
+
|
|
113
|
+
> **A field is editable if and only if it carries a write target.** The write target is set by whoever produced the data. Nothing downstream guesses.
|
|
114
|
+
|
|
115
|
+
- A **page field** (`fields.heading`) has no `ref`. Its write target is the page, and Composer already knows which page you are on.
|
|
116
|
+
- A **list row field** (`post.title`) carries `ref: { providerId, entity, id }` — the record it belongs to. Editing it saves to that record, not to the page.
|
|
117
|
+
- A row field the SDK could not trace back to a producer gets no `ref` and is marked `readOnly: true`. It renders as plain text in Composer: no outline, no click target.
|
|
118
|
+
|
|
119
|
+
You never set `ref` yourself. You never read it either. It is there so that the same `<Field>` you use for a page heading also works on a row in a list.
|
|
120
|
+
|
|
106
121
|
### Two ways to read a field
|
|
107
122
|
|
|
108
123
|
```tsx
|
|
@@ -130,8 +145,8 @@ export function Card({ fields }: { fields: Fields<{ title: string; link: string;
|
|
|
130
145
|
|
|
131
146
|
| Component | Field type | Renders |
|
|
132
147
|
| --- | --- | --- |
|
|
133
|
-
| `<Field>` | `string`, `number` |
|
|
134
|
-
| `<RichText>` | markdown / rich text | rendered HTML |
|
|
148
|
+
| `<Field>` | `string`, `number` | a `<span>` with the text |
|
|
149
|
+
| `<RichText>` | markdown / rich text | rendered HTML in a `<div>` (change with `as`) |
|
|
135
150
|
| `<Image>` | `ImageValue` | `<img>` |
|
|
136
151
|
|
|
137
152
|
All three take a `field` prop and read `name` from it. Pass any extra props (`className`, `loading`, etc.) and they go on the rendered element.
|
|
@@ -178,7 +193,7 @@ Why no `fallback` prop: a fallback turns "this field was never populated" into "
|
|
|
178
193
|
|
|
179
194
|
### Wrapper elements
|
|
180
195
|
|
|
181
|
-
`<Field>` renders
|
|
196
|
+
`<Field>` renders an inline `<span>`, never a heading or paragraph, so you supply the semantic tag around it:
|
|
182
197
|
|
|
183
198
|
```tsx
|
|
184
199
|
// ✓
|
|
@@ -189,6 +204,19 @@ Why no `fallback` prop: a fallback turns "this field was never populated" into "
|
|
|
189
204
|
<Field as="h1" field={fields.heading} />
|
|
190
205
|
```
|
|
191
206
|
|
|
207
|
+
`<RichText>` is the exception: it owns a block element, and `as` picks which one.
|
|
208
|
+
|
|
209
|
+
```tsx
|
|
210
|
+
// ✓ — default is <div>
|
|
211
|
+
<RichText field={fields.body} className="prose" />
|
|
212
|
+
|
|
213
|
+
// ✓ — pick a different block element
|
|
214
|
+
<RichText field={fields.body} as="article" className="prose" />
|
|
215
|
+
|
|
216
|
+
// ✗ — don't nest a block element inside a paragraph
|
|
217
|
+
<p><RichText field={fields.body} /></p>
|
|
218
|
+
```
|
|
219
|
+
|
|
192
220
|
If the wrapper should disappear when the field is empty, check `.value`:
|
|
193
221
|
|
|
194
222
|
```tsx
|
|
@@ -273,16 +301,18 @@ export function Announcement({ fields }: { fields: Fields<{ message: string }> }
|
|
|
273
301
|
export function Carousel({ fields }) {
|
|
274
302
|
const inComposer = useInComposer();
|
|
275
303
|
return (
|
|
276
|
-
|
|
277
|
-
{(slide) =>
|
|
278
|
-
|
|
304
|
+
<>
|
|
305
|
+
{(fields.slides.value ?? []).map((slide) => (
|
|
306
|
+
<Slide key={slide.id} slide={slide} autoplay={!inComposer} />
|
|
307
|
+
))}
|
|
308
|
+
</>
|
|
279
309
|
);
|
|
280
310
|
}
|
|
281
311
|
```
|
|
282
312
|
|
|
283
313
|
Rules of thumb:
|
|
284
314
|
|
|
285
|
-
- The **field component is the source of truth in Composer.** If a field is visible to authors, it must be rendered through `<Field>` / `<RichText>` / `<Image>`
|
|
315
|
+
- The **field component is the source of truth in Composer.** If a field is visible to authors, it must be rendered through `<Field>` / `<RichText>` / `<Image>` in Composer mode, even if the live site reads `.value`.
|
|
286
316
|
- **Don't fork the whole component.** Branch the one element that differs, not the entire return. Two divergent trees drift and the preview stops matching production.
|
|
287
317
|
- **Empty gating uses `inComposer`.** `if (!x.value) return null` is correct for live and wrong for authors — they can't click what isn't rendered. Add `&& !inComposer`.
|
|
288
318
|
- **Don't use it to hide editable text on live.** If the text is visible on the live site, render it with the field component in both modes. `useInComposer` is for content the live markup genuinely can't expose as a field.
|
|
@@ -299,20 +329,13 @@ Rules of thumb:
|
|
|
299
329
|
|
|
300
330
|
## Lists
|
|
301
331
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
| Shape | Schema | What it holds | In your component | Edited in Composer via |
|
|
305
|
-
| --- | --- | --- | --- | --- |
|
|
306
|
-
| **Reference list** | `array` + `entity` `of` | Linked entries — a query or a curated set of documents | Map `fields.posts.value` — plain rows | Props panel (pick, reorder) |
|
|
307
|
-
| **Repeater** | `array` + `of: 'json'` | Inline-authored items (slides, cards, FAQs) | `<Collection>` + `<Field>` on each item | Canvas (add, remove, reorder, click to edit) |
|
|
332
|
+
Every object array is a list of records. Each row is a fields object plus a plain `id`. Edit `post.title` in the grid and you are editing the post. Which records are in the list, and their order, is edited in the props panel — not on the canvas.
|
|
308
333
|
|
|
309
|
-
Scalar lists (tags, multi-select)
|
|
310
|
-
|
|
311
|
-
### Reference lists
|
|
312
|
-
|
|
313
|
-
Rows are plain objects, not envelopes. Read them directly:
|
|
334
|
+
Scalar lists (tags, multi-select) stay plain: `fields.tags` is `Field<string[]>`.
|
|
314
335
|
|
|
315
336
|
```tsx
|
|
337
|
+
import { Field, Image, RichText } from '@amplifyup/sdk/react';
|
|
338
|
+
|
|
316
339
|
export function LatestPosts({ fields }: { fields: Fields<{ heading: string; posts: Post[] }> }) {
|
|
317
340
|
const posts = fields.posts.value ?? [];
|
|
318
341
|
return (
|
|
@@ -321,8 +344,10 @@ export function LatestPosts({ fields }: { fields: Fields<{ heading: string; post
|
|
|
321
344
|
<ul>
|
|
322
345
|
{posts.map((post) => (
|
|
323
346
|
<li key={post.id}>
|
|
324
|
-
<
|
|
325
|
-
<a href={`/blog/${post.slug}`}>
|
|
347
|
+
<Image field={post.mainImage} />
|
|
348
|
+
<a href={`/blog/${post.slug}`}>
|
|
349
|
+
<Field field={post.title} />
|
|
350
|
+
</a>
|
|
326
351
|
</li>
|
|
327
352
|
))}
|
|
328
353
|
</ul>
|
|
@@ -332,75 +357,60 @@ export function LatestPosts({ fields }: { fields: Fields<{ heading: string; post
|
|
|
332
357
|
```
|
|
333
358
|
|
|
334
359
|
```tsx
|
|
335
|
-
// ✗ —
|
|
336
|
-
|
|
360
|
+
// ✗ — Field expects a scalar, not the list or the row
|
|
361
|
+
<Field field={fields.posts} />
|
|
362
|
+
<Field field={post} />
|
|
337
363
|
|
|
338
|
-
//
|
|
339
|
-
<
|
|
364
|
+
// ✓ — edit the record through its fields
|
|
365
|
+
<Field field={post.title} />
|
|
366
|
+
<Image field={post.mainImage} />
|
|
340
367
|
```
|
|
341
368
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
### Repeaters
|
|
345
|
-
|
|
346
|
-
Items **are** enveloped. `fields.slides.value[0].title` is `{ value, name: 'slides.0.title' }`. Render through `<Collection>`:
|
|
369
|
+
Search or load-more rows from `queryContent` are the same shape. Render them with the same components — one renderer for both:
|
|
347
370
|
|
|
348
371
|
```tsx
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
}) {
|
|
356
|
-
return (
|
|
357
|
-
<Collection field={fields.slides}>
|
|
358
|
-
{(slide, i) => (
|
|
359
|
-
<figure className="slide" data-index={i}>
|
|
360
|
-
<Image field={slide.image} />
|
|
361
|
-
<figcaption>
|
|
362
|
-
<h2><Field field={slide.title} /></h2>
|
|
363
|
-
<Field field={slide.caption} className="text-sm" />
|
|
364
|
-
</figcaption>
|
|
365
|
-
</figure>
|
|
366
|
-
)}
|
|
367
|
-
</Collection>
|
|
368
|
-
);
|
|
369
|
-
}
|
|
372
|
+
const posts = hits ?? fields.posts.value ?? [];
|
|
373
|
+
return posts.map((post) => (
|
|
374
|
+
<article key={post.id}>
|
|
375
|
+
<h2><Field field={post.title} /></h2>
|
|
376
|
+
</article>
|
|
377
|
+
));
|
|
370
378
|
```
|
|
371
379
|
|
|
372
|
-
|
|
380
|
+
### When a row is editable
|
|
373
381
|
|
|
374
|
-
|
|
382
|
+
A row is editable when the SDK knows which record it came from. That happens automatically in two cases:
|
|
375
383
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
<RichText field={q.answer} />
|
|
383
|
-
</li>
|
|
384
|
-
)}
|
|
385
|
-
</Collection>
|
|
386
|
-
</ul>
|
|
387
|
-
```
|
|
384
|
+
| Rows came from | Editable in Composer? |
|
|
385
|
+
| --- | --- |
|
|
386
|
+
| A list prop on your component (curated or query connection) | Yes |
|
|
387
|
+
| `queryContent` using the published spec from `{field}Pagination.spec` | Yes |
|
|
388
|
+
| `queryContent` with a spec you assembled by hand, missing `providerId` or `entity` | No — renders as plain text |
|
|
389
|
+
| Rows you fetched yourself from your CMS and passed in as props | No — renders as plain text |
|
|
388
390
|
|
|
389
|
-
|
|
390
|
-
// ✗ — mapping .value skips the canvas chrome; items won't be addable in Composer
|
|
391
|
-
{fields.slides.value.map((slide) => <Field field={slide.title} />)}
|
|
392
|
-
```
|
|
391
|
+
Read-only rows still render their text on the live site and in Composer. They just aren't clickable, and in development the SDK logs once per field:
|
|
393
392
|
|
|
394
|
-
|
|
393
|
+
```
|
|
394
|
+
[AmplifyUp SDK] title has no write target; rendered read-only.
|
|
395
|
+
```
|
|
395
396
|
|
|
396
|
-
|
|
397
|
+
If you see that and expected an editable field, the fix is upstream — use the published spec instead of a hand-built one, or bind the list to a connection in Composer. Do not try to add `ref` yourself.
|
|
397
398
|
|
|
398
399
|
```tsx
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
400
|
+
// ✓ — spec comes from the list prop Composer published; rows stay editable
|
|
401
|
+
const hits = await queryContent({
|
|
402
|
+
trackingId,
|
|
403
|
+
route: '/insights',
|
|
404
|
+
spec: searchSpec(postsPagination, 'title', term),
|
|
405
|
+
});
|
|
402
406
|
|
|
403
|
-
|
|
407
|
+
// ✗ — hand-built spec with no connection behind it; rows render read-only
|
|
408
|
+
const hits = await queryContent({
|
|
409
|
+
trackingId,
|
|
410
|
+
route: '/insights',
|
|
411
|
+
spec: { providerId: '', entity: '', filter: [], sort: [], limit: 10, offset: 0 },
|
|
412
|
+
});
|
|
413
|
+
```
|
|
404
414
|
|
|
405
415
|
---
|
|
406
416
|
|
|
@@ -409,19 +419,29 @@ No SDK component is involved on either path.
|
|
|
409
419
|
A slot is a region where authors drop other components. Render it with `<Slot>`:
|
|
410
420
|
|
|
411
421
|
```tsx
|
|
412
|
-
import {
|
|
422
|
+
import { Slot } from '@amplifyup/sdk/react';
|
|
413
423
|
|
|
414
|
-
export function TwoColumn(
|
|
424
|
+
export function TwoColumn() {
|
|
415
425
|
return (
|
|
416
426
|
<div className="grid grid-cols-2">
|
|
417
|
-
<div><Slot name="left"
|
|
418
|
-
<div><Slot name="right"
|
|
427
|
+
<div><Slot name="left" /></div>
|
|
428
|
+
<div><Slot name="right" /></div>
|
|
419
429
|
</div>
|
|
420
430
|
);
|
|
421
431
|
}
|
|
422
432
|
```
|
|
423
433
|
|
|
424
|
-
|
|
434
|
+
`<Slot>` takes only `name` and `className`. It reads the slot content from `ComponentContextProvider`, so you never thread a `slots` prop through your component.
|
|
435
|
+
|
|
436
|
+
```tsx
|
|
437
|
+
// ✗ — Slot has no `slots` prop
|
|
438
|
+
<Slot name="left" slots={slots} />
|
|
439
|
+
|
|
440
|
+
// ✓
|
|
441
|
+
<Slot name="left" />
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
Slot names must match the slots declared on the component in AmplifyUp. Slots hold components, not fields — nothing in a slot is read through `fields`.
|
|
425
445
|
|
|
426
446
|
---
|
|
427
447
|
|
|
@@ -434,24 +454,47 @@ Slots hold components, not fields — nothing in a slot is read through `fields`
|
|
|
434
454
|
| `{fields.x.value ?? 'default'}` in your code | expect the SDK to supply default copy |
|
|
435
455
|
| `if (!fields.x.value) return null` to hide a component | wrap `Field` in conditional logic that hides the field in Composer |
|
|
436
456
|
| `<h1><Field … /></h1>` | look for an `as` / `wrapper` prop |
|
|
437
|
-
|
|
|
438
|
-
| `<Collection>` for repeaters | `fields.slides.value.map(…)` for repeaters |
|
|
457
|
+
| `<Field field={post.title} />` in a list | `<Field field={fields.posts} />` or `<Field field={post} />` |
|
|
439
458
|
| `value` + `name` together for computed output | `value` alone, or `name` alone |
|
|
440
459
|
| `<Image field={fields.cover} />` | `<img src={fields.cover.value.url} />` when it should be editable |
|
|
441
|
-
| `queryContent` rows
|
|
460
|
+
| `queryContent` rows through `<Field field={post.title} />` | treat query rows as raw CMS objects |
|
|
461
|
+
| `spec: searchSpec(postsPagination, …)` from the published list prop | hand-build a `spec` and expect rows to stay editable |
|
|
462
|
+
| `<Slot name="left" />` | `<Slot name="left" slots={slots} />` |
|
|
463
|
+
| let the producer set `ref` | set, copy, or patch `ref` yourself |
|
|
442
464
|
| `useInComposer()` to expose a field the live markup can't (CSS background, attribute, hidden panel) | fork the whole component's return on `inComposer` |
|
|
443
465
|
| `if (!x.value && !inComposer) return null` | `if (!x.value) return null` — authors can't click what isn't rendered |
|
|
444
466
|
|
|
445
467
|
---
|
|
446
468
|
|
|
469
|
+
## Console messages
|
|
470
|
+
|
|
471
|
+
In development the SDK tells you exactly what is wrong. Production is silent.
|
|
472
|
+
|
|
473
|
+
| Message | What it means | Fix |
|
|
474
|
+
| --- | --- | --- |
|
|
475
|
+
| `Field expects a scalar field. Did you mean <Field field={post.title} />?` | You passed a list or a whole row to `Field` / `RichText` / `Image` | Pass one scalar field off the row |
|
|
476
|
+
| `title has no write target; rendered read-only.` | A row field the SDK can't trace to a record | Bind the list to a connection, or query with the published spec |
|
|
477
|
+
| `Field value={…} requires name="…" for computed values` | You passed `value` without `name` | Add `name={fields.x.name}` |
|
|
478
|
+
| `Field needs field={fields.yourProp} (or value + name for computed values)` | No binding at all | Pass `field=` |
|
|
479
|
+
| `Slot "left" used outside ComponentContextProvider` | The component wasn't wrapped when rendered | Wrap it in `renderComponent` |
|
|
480
|
+
|
|
481
|
+
---
|
|
482
|
+
|
|
447
483
|
## Types
|
|
448
484
|
|
|
449
485
|
```ts
|
|
450
486
|
import type { Field, Fields, ImageValue } from '@amplifyup/sdk/react';
|
|
451
487
|
|
|
452
|
-
type Field<T> = {
|
|
488
|
+
type Field<T> = {
|
|
489
|
+
value: T;
|
|
490
|
+
name: string;
|
|
491
|
+
/** Write target — the record this field saves to. Page fields omit it. */
|
|
492
|
+
ref?: { providerId: string; entity: string; id: string };
|
|
493
|
+
/** Row field with no write target — display only in Composer. */
|
|
494
|
+
readOnly?: true;
|
|
495
|
+
};
|
|
453
496
|
|
|
454
|
-
type Fields<T> = { [K in keyof T]: /* Field<T[K]>, recursing into objects and
|
|
497
|
+
type Fields<T> = { [K in keyof T]: /* Field<T[K]>, recursing into objects and lists */ };
|
|
455
498
|
```
|
|
456
499
|
|
|
457
500
|
Declare the schema shape once on the component and let inference do the rest:
|
|
@@ -462,14 +505,14 @@ type HeroFields = Fields<{
|
|
|
462
505
|
heading: string;
|
|
463
506
|
body: string; // markdown → use <RichText>
|
|
464
507
|
image: ImageValue; // → use <Image>
|
|
465
|
-
|
|
466
|
-
|
|
508
|
+
posts: Post[]; // list — each row is Fields<Post> & { id: string }
|
|
509
|
+
tags: string[]; // scalar list — Field<string[]>
|
|
467
510
|
}>;
|
|
468
511
|
|
|
469
512
|
export function Hero({ fields }: { fields: HeroFields }) { … }
|
|
470
513
|
```
|
|
471
514
|
|
|
472
|
-
`fields.heading.value` is `string
|
|
515
|
+
`fields.heading.value` is `string`. `fields.image.value` is `ImageValue | null`. `fields.posts.value[0]` is `Fields<Post> & { id: string }`. `fields.posts.value[0].title` is `Field<string>` with `ref` pointing at that post.
|
|
473
516
|
|
|
474
517
|
---
|
|
475
518
|
|
|
@@ -532,7 +575,9 @@ const hits = await queryContent({
|
|
|
532
575
|
});
|
|
533
576
|
```
|
|
534
577
|
|
|
535
|
-
Only entities published with that route can be queried, and visitors only see published content.
|
|
578
|
+
Only entities published with that route can be queried, and visitors only see published content. Also available from `@amplifyup/sdk/server`. See the [runtime queries guide](../../docs/sdk-site-setup.md#8-runtime-content-queries).
|
|
579
|
+
|
|
580
|
+
**Always start from `postsPagination.spec`.** `nextPageSpec` and `searchSpec` do that for you. The spec identifies the connection, and that is what makes the returned rows editable in Composer — see [when a row is editable](#when-a-row-is-editable). A spec you assemble by hand has no connection behind it, so its rows come back read-only.
|
|
536
581
|
|
|
537
582
|
## Track events
|
|
538
583
|
|
|
@@ -1,4 +1,40 @@
|
|
|
1
|
-
import 'react';
|
|
2
|
-
import 'react
|
|
3
|
-
|
|
4
|
-
import './types-
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
|
+
import { L as LayoutComponentProps, P as PageConfig } from './types-C32MgOiv.mjs';
|
|
5
|
+
|
|
6
|
+
interface AmplifyRendererProps {
|
|
7
|
+
/**
|
|
8
|
+
* Component renderer function that maps componentId to React component
|
|
9
|
+
* This is site-specific and must be provided by the developer
|
|
10
|
+
*/
|
|
11
|
+
renderComponent: (componentId: string, props: LayoutComponentProps, slots?: Record<string, ReactNode>, context?: {
|
|
12
|
+
layoutNodeId: string;
|
|
13
|
+
}) => ReactNode;
|
|
14
|
+
/**
|
|
15
|
+
* Optional page config for server-side rendering (SSR/SSG)
|
|
16
|
+
* If provided, the component will use this instead of fetching client-side
|
|
17
|
+
*/
|
|
18
|
+
pageConfig?: PageConfig;
|
|
19
|
+
/**
|
|
20
|
+
* Optional loading component
|
|
21
|
+
*/
|
|
22
|
+
loadingComponent?: ReactNode;
|
|
23
|
+
/**
|
|
24
|
+
* Optional error component
|
|
25
|
+
*/
|
|
26
|
+
errorComponent?: (error: string) => ReactNode;
|
|
27
|
+
/**
|
|
28
|
+
* Optional empty state component (when no content is configured)
|
|
29
|
+
*/
|
|
30
|
+
emptyComponent?: ReactNode;
|
|
31
|
+
/**
|
|
32
|
+
* Force Composer page-slot wrapper (avoids SSR miss when window isn't available yet).
|
|
33
|
+
* When true, root components stay under [data-slot-source="page"] so hierarchy can climb to Page.
|
|
34
|
+
*/
|
|
35
|
+
composerPreview?: boolean;
|
|
36
|
+
}
|
|
37
|
+
declare function AmplifyRendererInner({ renderComponent, pageConfig: serverPageConfig, loadingComponent, errorComponent, emptyComponent, composerPreview, }: AmplifyRendererProps): react_jsx_runtime.JSX.Element | null;
|
|
38
|
+
declare const AmplifyRenderer: react.MemoExoticComponent<typeof AmplifyRendererInner>;
|
|
39
|
+
|
|
40
|
+
export { AmplifyRenderer };
|
|
@@ -1,4 +1,40 @@
|
|
|
1
|
-
import 'react';
|
|
2
|
-
import 'react
|
|
3
|
-
|
|
4
|
-
import './types-
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
|
+
import { L as LayoutComponentProps, P as PageConfig } from './types-C32MgOiv.js';
|
|
5
|
+
|
|
6
|
+
interface AmplifyRendererProps {
|
|
7
|
+
/**
|
|
8
|
+
* Component renderer function that maps componentId to React component
|
|
9
|
+
* This is site-specific and must be provided by the developer
|
|
10
|
+
*/
|
|
11
|
+
renderComponent: (componentId: string, props: LayoutComponentProps, slots?: Record<string, ReactNode>, context?: {
|
|
12
|
+
layoutNodeId: string;
|
|
13
|
+
}) => ReactNode;
|
|
14
|
+
/**
|
|
15
|
+
* Optional page config for server-side rendering (SSR/SSG)
|
|
16
|
+
* If provided, the component will use this instead of fetching client-side
|
|
17
|
+
*/
|
|
18
|
+
pageConfig?: PageConfig;
|
|
19
|
+
/**
|
|
20
|
+
* Optional loading component
|
|
21
|
+
*/
|
|
22
|
+
loadingComponent?: ReactNode;
|
|
23
|
+
/**
|
|
24
|
+
* Optional error component
|
|
25
|
+
*/
|
|
26
|
+
errorComponent?: (error: string) => ReactNode;
|
|
27
|
+
/**
|
|
28
|
+
* Optional empty state component (when no content is configured)
|
|
29
|
+
*/
|
|
30
|
+
emptyComponent?: ReactNode;
|
|
31
|
+
/**
|
|
32
|
+
* Force Composer page-slot wrapper (avoids SSR miss when window isn't available yet).
|
|
33
|
+
* When true, root components stay under [data-slot-source="page"] so hierarchy can climb to Page.
|
|
34
|
+
*/
|
|
35
|
+
composerPreview?: boolean;
|
|
36
|
+
}
|
|
37
|
+
declare function AmplifyRendererInner({ renderComponent, pageConfig: serverPageConfig, loadingComponent, errorComponent, emptyComponent, composerPreview, }: AmplifyRendererProps): react_jsx_runtime.JSX.Element | null;
|
|
38
|
+
declare const AmplifyRenderer: react.MemoExoticComponent<typeof AmplifyRendererInner>;
|
|
39
|
+
|
|
40
|
+
export { AmplifyRenderer };
|