@amplifyup/sdk 0.1.62 → 0.1.64

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/dist/react.js CHANGED
@@ -413,6 +413,16 @@ function isComposerPreview() {
413
413
 
414
414
  // src/field-envelope.ts
415
415
  var FIELDS_BRAND = Symbol("amplifyup.fields");
416
+ var IDENTIFIER_KEYS = /* @__PURE__ */ new Set([
417
+ "id",
418
+ "_id",
419
+ "slug",
420
+ "key",
421
+ "_key",
422
+ "docId",
423
+ "_type",
424
+ "type"
425
+ ]);
416
426
  function isBrandedFields(value) {
417
427
  return !!value && typeof value === "object" && FIELDS_BRAND in value;
418
428
  }
@@ -434,6 +444,79 @@ function isPortableImageShape(value) {
434
444
  if (!value || typeof value !== "object" || Array.isArray(value)) return false;
435
445
  return "url" in value;
436
446
  }
447
+ function isIdentifierKey(key) {
448
+ return IDENTIFIER_KEYS.has(key);
449
+ }
450
+ function isRecordList(value) {
451
+ if (!Array.isArray(value) || value.length === 0) return false;
452
+ const sample = value.find((item) => item != null);
453
+ if (sample === void 0) return false;
454
+ if (typeof sample !== "object" || Array.isArray(sample)) return false;
455
+ if (isPortableImageShape(sample)) return false;
456
+ if (sample.$$typeof) return false;
457
+ return true;
458
+ }
459
+ function isFieldRef(value) {
460
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
461
+ const rec = value;
462
+ return typeof rec.providerId === "string" && !!rec.providerId && typeof rec.entity === "string" && !!rec.entity && typeof rec.id === "string" && !!rec.id;
463
+ }
464
+ function isListOwner(value) {
465
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
466
+ const rec = value;
467
+ return typeof rec.providerId === "string" && !!rec.providerId && typeof rec.entity === "string" && !!rec.entity;
468
+ }
469
+ function isReadOnlyRowField(value) {
470
+ return isFieldEnvelope(value) && value.readOnly === true && !value.ref;
471
+ }
472
+ function composerStoreKey(name, ref, layoutNodeId) {
473
+ if (isFieldRef(ref)) {
474
+ return `record:${ref.providerId}:${ref.entity}:${ref.id}:${name}`;
475
+ }
476
+ return layoutNodeId ? `page:${layoutNodeId}:${name}` : name;
477
+ }
478
+ function listOwnerFromConnection(conn) {
479
+ if (!conn || typeof conn !== "object") return void 0;
480
+ if (conn.mode === "query") {
481
+ const providerId = String(conn.spec?.providerId || "").trim();
482
+ const entity = String(conn.spec?.entity || "").trim();
483
+ return providerId && entity ? { providerId, entity } : void 0;
484
+ }
485
+ if (conn.mode === "item" || conn.mode === "items") {
486
+ const providerId = String(conn.providerId || "").trim();
487
+ const entity = String(conn.entity || "").trim();
488
+ return providerId && entity ? { providerId, entity } : void 0;
489
+ }
490
+ return void 0;
491
+ }
492
+ function listOwnerFromSpec(spec) {
493
+ const providerId = String(spec?.providerId || "").trim();
494
+ const entity = String(spec?.entity || "").trim();
495
+ return providerId && entity ? { providerId, entity } : void 0;
496
+ }
497
+ function isEnvelopeSources(value) {
498
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
499
+ const rec = value;
500
+ return rec.connections != null || rec.reads != null;
501
+ }
502
+ function normalizeEnvelopeSources(sources) {
503
+ if (!sources) return {};
504
+ if (isEnvelopeSources(sources) && !("mode" in sources)) {
505
+ return sources;
506
+ }
507
+ return { connections: sources };
508
+ }
509
+ function listOwnerForField(fieldName, props, sources) {
510
+ const { connections, reads } = normalizeEnvelopeSources(sources);
511
+ const resourceName = reads?.[fieldName]?.resource || fieldName;
512
+ const fromConn = listOwnerFromConnection(connections?.[resourceName]);
513
+ if (fromConn) return fromConn;
514
+ const paging = props?.[`${fieldName}Pagination`];
515
+ if (paging && typeof paging === "object" && !Array.isArray(paging)) {
516
+ return listOwnerFromSpec(paging.spec);
517
+ }
518
+ return void 0;
519
+ }
437
520
  function joinPath(prefix, key) {
438
521
  return prefix ? `${prefix}.${key}` : key;
439
522
  }
@@ -441,39 +524,101 @@ function emptyValue(raw) {
441
524
  if (raw === void 0) return null;
442
525
  return raw;
443
526
  }
444
- function toFieldEnvelopes(source, prefix = "") {
527
+ function rowId(raw) {
528
+ const candidates = [raw.id, raw._id, raw.docId, raw.key, raw._key];
529
+ for (const c of candidates) {
530
+ if (typeof c === "string" && c.trim()) return c;
531
+ }
532
+ return "";
533
+ }
534
+ function withLeaf(envelope, scope) {
535
+ if (isFieldRef(scope?.ref)) envelope.ref = scope.ref;
536
+ else if (scope?.readOnly) envelope.readOnly = true;
537
+ return envelope;
538
+ }
539
+ function toFieldEnvelopes(source, prefix = "", scope) {
540
+ const ctx = isFieldRef(scope) ? { ref: scope } : scope || {};
445
541
  const input = source && typeof source === "object" && !Array.isArray(source) ? source : {};
446
542
  if (isBrandedFields(input)) {
447
543
  return input;
448
544
  }
449
545
  const out = {};
450
546
  for (const [key, raw] of Object.entries(input)) {
547
+ if (isIdentifierKey(key) && (typeof raw === "string" || raw == null)) {
548
+ out[key] = raw ?? "";
549
+ continue;
550
+ }
451
551
  const path = joinPath(prefix, key);
452
552
  if (isFieldEnvelope(raw)) {
453
- out[key] = { value: raw.value ?? null, name: raw.name || path };
553
+ const inner = raw.value;
554
+ if (isRecordList(inner)) {
555
+ const owner = ctx.owners?.(key);
556
+ out[key] = {
557
+ value: envelopeListRows(inner, owner),
558
+ name: raw.name || path
559
+ };
560
+ continue;
561
+ }
562
+ out[key] = withLeaf(
563
+ { value: raw.value ?? null, name: raw.name || path },
564
+ raw.ref ? { ref: raw.ref } : ctx
565
+ );
566
+ continue;
567
+ }
568
+ if (isRecordList(raw)) {
569
+ const owner = ctx.owners?.(key);
570
+ out[key] = { value: envelopeListRows(raw, owner), name: path };
454
571
  continue;
455
572
  }
456
573
  if (raw && typeof raw === "object" && !Array.isArray(raw) && !isPortableImageShape(raw) && !raw.$$typeof) {
457
- out[key] = toFieldEnvelopes(raw, path);
574
+ out[key] = toFieldEnvelopes(raw, path, ctx);
458
575
  continue;
459
576
  }
460
- out[key] = { value: emptyValue(raw), name: path };
577
+ out[key] = withLeaf({ value: emptyValue(raw), name: path }, ctx);
461
578
  }
462
579
  return brandFields(out);
463
580
  }
464
- function attachFieldEnvelopes(props) {
581
+ function envelopeListRows(items, owner) {
582
+ return items.map((item) => envelopeListRow(item, owner));
583
+ }
584
+ function envelopeListRow(item, owner) {
585
+ if (isBrandedFields(item) && typeof item.id === "string") {
586
+ return item;
587
+ }
588
+ const raw = item && typeof item === "object" && !Array.isArray(item) ? item : {};
589
+ const id = rowId(raw);
590
+ const ref = isListOwner(owner) && id ? { providerId: owner.providerId, entity: owner.entity, id } : void 0;
591
+ const fields = toFieldEnvelopes(raw, "", {
592
+ ref,
593
+ readOnly: !ref
594
+ });
595
+ const row = fields;
596
+ if (typeof row.id !== "string") {
597
+ row.id = id;
598
+ }
599
+ return row;
600
+ }
601
+ function attachFieldEnvelopes(props, sources) {
465
602
  const raw = props && typeof props === "object" ? { ...props } : {};
466
603
  if (isBrandedFields(raw.fields)) return raw;
467
604
  const { fields: existing, ...content } = raw;
468
605
  const source = existing && typeof existing === "object" && !isFieldEnvelope(existing) ? existing : content;
469
- return { ...raw, fields: toFieldEnvelopes(source) };
606
+ return {
607
+ ...raw,
608
+ fields: toFieldEnvelopes(source, "", {
609
+ owners: (fieldName) => listOwnerForField(fieldName, source, sources)
610
+ })
611
+ };
470
612
  }
471
613
  function walkLayoutNodes(nodes) {
472
614
  if (!Array.isArray(nodes)) return;
473
615
  for (const node of nodes) {
474
616
  if (!node || typeof node !== "object") continue;
475
617
  const rec = node;
476
- rec.props = attachFieldEnvelopes(rec.props);
618
+ rec.props = attachFieldEnvelopes(rec.props, {
619
+ connections: rec.resources,
620
+ reads: rec.reads
621
+ });
477
622
  for (const slot of rec.slots || []) {
478
623
  walkLayoutNodes(slot.children);
479
624
  }
@@ -487,15 +632,36 @@ function envelopePageConfig(page) {
487
632
  }
488
633
  function collectFieldPatches(props) {
489
634
  const out = [];
635
+ const walkRows = (items) => {
636
+ for (const item of items) {
637
+ if (isBrandedFields(item) || item && typeof item === "object" && !Array.isArray(item) && !isFieldEnvelope(item)) {
638
+ walk(item, "");
639
+ }
640
+ }
641
+ };
490
642
  const walk = (obj, prefix) => {
491
643
  for (const [key, raw] of Object.entries(obj)) {
644
+ if (isIdentifierKey(key)) continue;
492
645
  if (key === "fields" && raw && typeof raw === "object" && !Array.isArray(raw) && !isFieldEnvelope(raw)) {
493
646
  walk(raw, prefix);
494
647
  continue;
495
648
  }
496
649
  const path = joinPath(prefix, key);
497
650
  if (isFieldEnvelope(raw)) {
498
- out.push({ name: raw.name || path, value: raw.value });
651
+ if (isRecordList(raw.value)) {
652
+ walkRows(raw.value);
653
+ continue;
654
+ }
655
+ const patch = {
656
+ name: raw.name || path,
657
+ value: raw.value
658
+ };
659
+ if (raw.ref) patch.ref = raw.ref;
660
+ out.push(patch);
661
+ continue;
662
+ }
663
+ if (isRecordList(raw)) {
664
+ walkRows(raw);
499
665
  continue;
500
666
  }
501
667
  if (raw && typeof raw === "object" && !Array.isArray(raw) && !isPortableImageShape(raw) && !raw.$$typeof) {
@@ -512,7 +678,12 @@ function collectFieldPatches(props) {
512
678
  }
513
679
  function resolveEditableBinding(field, value, name) {
514
680
  if (isFieldEnvelope(field)) {
515
- return { name: field.name, value: field.value, requiresName: false };
681
+ return {
682
+ name: field.name,
683
+ value: field.value,
684
+ ref: field.ref,
685
+ requiresName: false
686
+ };
516
687
  }
517
688
  return {
518
689
  name: name || "",
@@ -871,7 +1042,10 @@ async function fetchEdgeResolve(options) {
871
1042
  return envelopeResolvedPayload(body);
872
1043
  }
873
1044
  function envelopeResolvedComponent(node) {
874
- node.props = attachFieldEnvelopes(node.props);
1045
+ node.props = attachFieldEnvelopes(node.props, {
1046
+ connections: node.resources,
1047
+ reads: node.reads
1048
+ });
875
1049
  if (!node.children) return;
876
1050
  for (const kids of Object.values(node.children)) {
877
1051
  for (const child of kids || []) envelopeResolvedComponent(child);
@@ -1130,7 +1304,7 @@ async function fetchEdgeQuery(options) {
1130
1304
  async function queryContent(options) {
1131
1305
  const target = resolveAmplifyUpTarget({ configTarget: options.target });
1132
1306
  const { edgeUrl } = resolveAmplifyUpUrls(target);
1133
- return fetchEdgeQuery({
1307
+ const raw = await fetchEdgeQuery({
1134
1308
  edgeUrl,
1135
1309
  trackingId: options.trackingId,
1136
1310
  route: options.route,
@@ -1139,6 +1313,13 @@ async function queryContent(options) {
1139
1313
  fetch: options.fetch,
1140
1314
  signal: options.signal
1141
1315
  });
1316
+ return {
1317
+ ...raw,
1318
+ results: envelopeListRows(
1319
+ raw.results,
1320
+ listOwnerFromSpec(options.spec)
1321
+ )
1322
+ };
1142
1323
  }
1143
1324
  function nextPageSpec(pagination) {
1144
1325
  return { ...pagination.spec, offset: pagination.nextOffset };
@@ -3623,39 +3804,62 @@ var ComposerFieldStore = class {
3623
3804
  if (set.size === 0) this.listeners.delete(name);
3624
3805
  };
3625
3806
  }
3807
+ keys() {
3808
+ return [...this.values.keys()];
3809
+ }
3810
+ delete(name) {
3811
+ if (!name || !this.values.has(name)) return;
3812
+ this.values.delete(name);
3813
+ const set = this.listeners.get(name);
3814
+ if (!set) return;
3815
+ for (const fn of set) fn();
3816
+ }
3626
3817
  };
3627
3818
  var ComposerStoreContext = React2.createContext(null);
3628
- function matchesNode(eventNodeId, layoutNodeId) {
3629
- if (eventNodeId && layoutNodeId && String(eventNodeId) !== String(layoutNodeId)) {
3630
- return false;
3631
- }
3632
- return true;
3819
+ var ComposerNodeContext = React2.createContext(void 0);
3820
+ function applyComposerPatch(store, name, value, ref, layoutNodeId) {
3821
+ store.set(composerStoreKey(name, ref, layoutNodeId), value);
3633
3822
  }
3634
3823
  function ComposerProvider({
3635
- layoutNodeId,
3636
3824
  children
3637
3825
  }) {
3826
+ const existing = React2.useContext(ComposerStoreContext);
3638
3827
  const storeRef = React2.useRef(null);
3639
3828
  if (!storeRef.current) storeRef.current = new ComposerFieldStore();
3640
- const store = storeRef.current;
3829
+ const store = existing || storeRef.current;
3641
3830
  React2.useEffect(() => {
3642
- const applyField = (fieldName, value, nodeId) => {
3831
+ if (existing) return;
3832
+ const applyField = (fieldName, value, nodeId, ref) => {
3643
3833
  if (!fieldName || typeof fieldName !== "string") return;
3644
- if (!matchesNode(nodeId, layoutNodeId)) return;
3645
- store.set(fieldName, value);
3834
+ const fieldRef = isFieldRef(ref) ? ref : void 0;
3835
+ const layoutNodeId = typeof nodeId === "string" && nodeId ? nodeId : void 0;
3836
+ applyComposerPatch(store, fieldName, value, fieldRef, layoutNodeId);
3646
3837
  };
3647
3838
  const applyProps = (nextProps, nodeId) => {
3648
3839
  if (!nextProps || typeof nextProps !== "object" || Array.isArray(nextProps)) {
3649
3840
  return;
3650
3841
  }
3651
- if (!matchesNode(nodeId, layoutNodeId)) return;
3652
- for (const patch of collectFieldPatches(nextProps)) {
3653
- store.set(patch.name, patch.value);
3842
+ const layoutNodeId = typeof nodeId === "string" && nodeId ? nodeId : void 0;
3843
+ for (const patch of collectFieldPatches(
3844
+ nextProps
3845
+ )) {
3846
+ applyComposerPatch(
3847
+ store,
3848
+ patch.name,
3849
+ patch.value,
3850
+ patch.ref,
3851
+ patch.ref ? void 0 : layoutNodeId
3852
+ );
3654
3853
  }
3655
3854
  };
3656
3855
  const onPatch = (event) => {
3657
3856
  const detail = event.detail || {};
3658
- applyField(detail.fieldName, detail.value, detail.layoutNodeId);
3857
+ applyField(
3858
+ detail.fieldName,
3859
+ detail.value,
3860
+ detail.layoutNodeId,
3861
+ detail.ref
3862
+ );
3659
3863
  };
3660
3864
  const onPropsPatch = (event) => {
3661
3865
  const detail = event.detail || {};
@@ -3667,7 +3871,12 @@ function ComposerProvider({
3667
3871
  return;
3668
3872
  }
3669
3873
  if (event.data?.type !== "AMPLIFYUP_FIELD_PATCH") return;
3670
- applyField(event.data.fieldName, event.data.value, event.data.layoutNodeId);
3874
+ applyField(
3875
+ event.data.fieldName,
3876
+ event.data.value,
3877
+ event.data.layoutNodeId,
3878
+ event.data.ref
3879
+ );
3671
3880
  };
3672
3881
  window.addEventListener("amplifyup:field-patch", onPatch);
3673
3882
  window.addEventListener("amplifyup:props-patch", onPropsPatch);
@@ -3677,23 +3886,26 @@ function ComposerProvider({
3677
3886
  window.removeEventListener("amplifyup:props-patch", onPropsPatch);
3678
3887
  window.removeEventListener("message", onMessage);
3679
3888
  };
3680
- }, [layoutNodeId, store]);
3889
+ }, [existing, store]);
3890
+ if (existing) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
3681
3891
  return /* @__PURE__ */ jsxRuntime.jsx(ComposerStoreContext.Provider, { value: store, children });
3682
3892
  }
3683
- function useComposerFieldValue(name, fallback) {
3893
+ function useComposerFieldValue(name, fallback, ref) {
3684
3894
  const store = React2.useContext(ComposerStoreContext);
3895
+ const layoutNodeId = React2.useContext(ComposerNodeContext);
3896
+ const key = composerStoreKey(name, ref, layoutNodeId);
3685
3897
  const subscribe = React2.useCallback(
3686
3898
  (onStoreChange) => {
3687
3899
  if (!store || !name) return () => {
3688
3900
  };
3689
- return store.subscribe(name, onStoreChange);
3901
+ return store.subscribe(key, onStoreChange);
3690
3902
  },
3691
- [store, name]
3903
+ [store, name, key]
3692
3904
  );
3693
3905
  const getSnapshot = React2.useCallback(() => {
3694
3906
  if (!store || !name) return void 0;
3695
- return store.get(name);
3696
- }, [store, name]);
3907
+ return store.get(key);
3908
+ }, [store, name, key]);
3697
3909
  const overlay = React2.useSyncExternalStore(subscribe, getSnapshot, () => void 0);
3698
3910
  return overlay !== void 0 ? overlay : fallback;
3699
3911
  }
@@ -3704,7 +3916,7 @@ function MaybeComposerProvider({
3704
3916
  }) {
3705
3917
  const content = React2.useMemo(() => children, [children]);
3706
3918
  if (!enabled) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: content });
3707
- return /* @__PURE__ */ jsxRuntime.jsx(ComposerProvider, { layoutNodeId, children });
3919
+ return /* @__PURE__ */ jsxRuntime.jsx(ComposerProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(ComposerNodeContext.Provider, { value: layoutNodeId, children }) });
3708
3920
  }
3709
3921
  function nodeRenderProps(node) {
3710
3922
  const settings = node.settings || {};
@@ -4162,7 +4374,7 @@ function AmplifyRendererInner({
4162
4374
  if (layoutTree.length === 0) {
4163
4375
  return /* @__PURE__ */ jsxRuntime.jsx("main", { children: emptyComponent || /* @__PURE__ */ jsxRuntime.jsx("div", { className: "container mx-auto px-4 py-16", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: "No content configured for this page." }) }) });
4164
4376
  }
4165
- return /* @__PURE__ */ jsxRuntime.jsx("main", { children: composerPreview || isComposerPreview() ? /* @__PURE__ */ jsxRuntime.jsx(
4377
+ return /* @__PURE__ */ jsxRuntime.jsx(ComposerProvider, { children: /* @__PURE__ */ jsxRuntime.jsx("main", { children: composerPreview || isComposerPreview() ? /* @__PURE__ */ jsxRuntime.jsx(
4166
4378
  "div",
4167
4379
  {
4168
4380
  "data-slot-id": "main",
@@ -4171,7 +4383,7 @@ function AmplifyRendererInner({
4171
4383
  "data-slot-empty": layoutTree.length === 0 ? "true" : void 0,
4172
4384
  children: layoutTree.map((node) => /* @__PURE__ */ jsxRuntime.jsx(React2.Fragment, { children: renderNode(node) }, node.id))
4173
4385
  }
4174
- ) : layoutTree.map((node) => /* @__PURE__ */ jsxRuntime.jsx(React2.Fragment, { children: renderNode(node) }, node.id)) });
4386
+ ) : layoutTree.map((node) => /* @__PURE__ */ jsxRuntime.jsx(React2.Fragment, { children: renderNode(node) }, node.id)) }) });
4175
4387
  }
4176
4388
  var AmplifyRenderer = React2.memo(AmplifyRendererInner);
4177
4389
  function AddComponentIcon({ size = 28 }) {
@@ -4360,6 +4572,21 @@ function AmplifyPageContent({
4360
4572
  }
4361
4573
  );
4362
4574
  }
4575
+
4576
+ // src/composer-edit-mode.ts
4577
+ function isComposerEditMode() {
4578
+ if (typeof window === "undefined") return false;
4579
+ return isComposerPreview() && window.__AMPLIFYUP_EVENT_SELECTION__ !== true;
4580
+ }
4581
+ function subscribeComposerEdit(onStoreChange) {
4582
+ if (typeof window === "undefined") return () => {
4583
+ };
4584
+ window.addEventListener("amplifyup:composer-edit", onStoreChange);
4585
+ return () => window.removeEventListener("amplifyup:composer-edit", onStoreChange);
4586
+ }
4587
+ function getComposerEditModeServer() {
4588
+ return false;
4589
+ }
4363
4590
  var ComponentContext = React2.createContext(null);
4364
4591
  function ComponentContextProvider({
4365
4592
  children,
@@ -4461,10 +4688,6 @@ function Slot({
4461
4688
  }
4462
4689
  );
4463
4690
  }
4464
- function isComposerEditMode() {
4465
- if (typeof window === "undefined") return false;
4466
- return isComposerPreview() && window.__AMPLIFYUP_EVENT_SELECTION__ !== true;
4467
- }
4468
4691
  function isLikelyNonTextFieldName(name) {
4469
4692
  const n = name.toLowerCase();
4470
4693
  return n.includes("href") || n.includes("url") || n.includes("src") || n.includes("image") || n.includes("icon") || n.includes("overlay") || n.includes("color");
@@ -4499,17 +4722,11 @@ function canInlineEditRichText(name, value) {
4499
4722
  }
4500
4723
  return true;
4501
4724
  }
4502
- function subscribeComposerEdit(onStoreChange) {
4503
- if (typeof window === "undefined") return () => {
4504
- };
4505
- window.addEventListener("amplifyup:composer-edit", onStoreChange);
4506
- return () => window.removeEventListener("amplifyup:composer-edit", onStoreChange);
4507
- }
4508
4725
  function useComposerEditMode() {
4509
4726
  return React2.useSyncExternalStore(
4510
4727
  subscribeComposerEdit,
4511
4728
  isComposerEditMode,
4512
- () => false
4729
+ getComposerEditModeServer
4513
4730
  );
4514
4731
  }
4515
4732
  function useBoundField(field, value, name, component) {
@@ -4519,10 +4736,10 @@ function useBoundField(field, value, name, component) {
4519
4736
  `[AmplifyUp SDK] ${component} value={\u2026} requires name="\u2026" for computed values`
4520
4737
  );
4521
4738
  }
4522
- const fieldValue = useComposerFieldValue(bound.name, bound.value);
4523
- return { editName: bound.name, fieldValue };
4739
+ const fieldValue = useComposerFieldValue(bound.name, bound.value, bound.ref);
4740
+ return { editName: bound.name, fieldValue, ref: bound.ref };
4524
4741
  }
4525
- function commitComposerField(layoutNodeId, componentId, name, value) {
4742
+ function commitComposerField(layoutNodeId, componentId, name, value, ref) {
4526
4743
  if (typeof window === "undefined" || window.parent === window) return;
4527
4744
  window.parent.postMessage(
4528
4745
  {
@@ -4530,7 +4747,8 @@ function commitComposerField(layoutNodeId, componentId, name, value) {
4530
4747
  layoutNodeId,
4531
4748
  componentId,
4532
4749
  fieldName: name,
4533
- value
4750
+ value,
4751
+ ...ref ? { ref } : {}
4534
4752
  },
4535
4753
  "*"
4536
4754
  );
@@ -4555,6 +4773,7 @@ function requestCanvasRichTextEdit(opts) {
4555
4773
  componentId: opts.componentId,
4556
4774
  fieldName: opts.name,
4557
4775
  value: opts.value,
4776
+ ...opts.fieldRef ? { ref: opts.fieldRef } : {},
4558
4777
  bounds: {
4559
4778
  top: rect.top,
4560
4779
  left: rect.left,
@@ -4577,23 +4796,21 @@ function ComposerInlineField({
4577
4796
  name,
4578
4797
  value,
4579
4798
  className,
4580
- render,
4581
4799
  layoutNodeId,
4582
4800
  componentId,
4801
+ fieldRef,
4583
4802
  rich = false
4584
4803
  }) {
4585
- const [editing, setEditing] = React2.useState(false);
4586
4804
  const [focused, setFocused] = React2.useState(false);
4587
4805
  const elRef = React2.useRef(null);
4588
4806
  const storedEmpty = isComposerEmptyText(value);
4589
4807
  const text = storedEmpty ? "" : formatFieldValue(value);
4590
4808
  const hint = COMPOSER_EMPTY_FIELD_HINT;
4591
4809
  const idleDisplay = storedEmpty ? hint : text;
4592
- const showRendered = !!render && !editing && !storedEmpty;
4593
- const showHint = storedEmpty && !focused && !showRendered;
4810
+ const showHint = storedEmpty && !focused;
4594
4811
  React2.useEffect(() => {
4595
4812
  const el = elRef.current;
4596
- if (!el || showRendered) return;
4813
+ if (!el) return;
4597
4814
  if (document.activeElement === el) return;
4598
4815
  if (el.querySelector(
4599
4816
  "input, button, select, textarea, form, svg, iframe, img"
@@ -4602,34 +4819,20 @@ function ComposerInlineField({
4602
4819
  }
4603
4820
  const next = idleDisplay || "";
4604
4821
  if (el.textContent !== next) el.textContent = next;
4605
- }, [idleDisplay, showRendered]);
4606
- React2.useEffect(() => {
4607
- if (!editing || !elRef.current) return;
4608
- const el = elRef.current;
4609
- if (storedEmpty) {
4610
- el.textContent = "";
4611
- el.focus();
4612
- placeCaret(el, true);
4613
- return;
4614
- }
4615
- el.textContent = idleDisplay || "";
4616
- el.focus();
4617
- placeCaret(el, false);
4618
- }, [editing, storedEmpty, idleDisplay]);
4822
+ }, [idleDisplay]);
4619
4823
  const finishEdit = () => {
4620
4824
  const raw = (elRef.current?.innerText ?? "").replace(/\u00a0/g, " ").replace(/\n+$/g, "");
4621
4825
  const next = raw.trim() === "" ? "" : raw;
4622
- setEditing(false);
4623
4826
  setFocused(false);
4624
4827
  if (storedEmpty && next === "") {
4625
4828
  if (elRef.current) elRef.current.textContent = hint;
4626
4829
  if (typeof value === "string" && EMPTY_FIELD_PLACEHOLDERS.has(value.trim())) {
4627
- commitComposerField(layoutNodeId, componentId, name, "");
4830
+ commitComposerField(layoutNodeId, componentId, name, "", fieldRef);
4628
4831
  }
4629
4832
  return;
4630
4833
  }
4631
4834
  if (next === text) return;
4632
- commitComposerField(layoutNodeId, componentId, name, next);
4835
+ commitComposerField(layoutNodeId, componentId, name, next, fieldRef);
4633
4836
  };
4634
4837
  const openRichEditor = (event) => {
4635
4838
  if (!isComposerEditMode() || !elRef.current) return;
@@ -4641,7 +4844,8 @@ function ComposerInlineField({
4641
4844
  layoutNodeId,
4642
4845
  componentId,
4643
4846
  name,
4644
- value: source
4847
+ value: source,
4848
+ fieldRef
4645
4849
  });
4646
4850
  };
4647
4851
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -4652,8 +4856,11 @@ function ComposerInlineField({
4652
4856
  "data-amplifyup-field": name,
4653
4857
  "data-amplifyup-field-type": rich ? "richtext" : "text",
4654
4858
  "data-amplifyup-node-id": layoutNodeId || void 0,
4859
+ "data-amplifyup-ref-provider": fieldRef?.providerId || void 0,
4860
+ "data-amplifyup-ref-entity": fieldRef?.entity || void 0,
4861
+ "data-amplifyup-ref-id": fieldRef?.id || void 0,
4655
4862
  "data-amplifyup-empty-hint": showHint ? "true" : void 0,
4656
- contentEditable: !rich && !showRendered,
4863
+ contentEditable: !rich,
4657
4864
  suppressContentEditableWarning: true,
4658
4865
  role: "textbox",
4659
4866
  tabIndex: 0,
@@ -4668,9 +4875,6 @@ function ComposerInlineField({
4668
4875
  openRichEditor(event);
4669
4876
  return;
4670
4877
  }
4671
- if (render) {
4672
- setEditing(true);
4673
- }
4674
4878
  },
4675
4879
  onFocus: () => {
4676
4880
  if (!isComposerEditMode()) return;
@@ -4684,7 +4888,6 @@ function ComposerInlineField({
4684
4888
  el.textContent = "";
4685
4889
  placeCaret(el, true);
4686
4890
  }
4687
- if (render) setEditing(true);
4688
4891
  },
4689
4892
  onBlur: rich ? void 0 : finishEdit,
4690
4893
  onKeyDown: (event) => {
@@ -4696,7 +4899,6 @@ function ComposerInlineField({
4696
4899
  if (event.key === "Escape") {
4697
4900
  event.preventDefault();
4698
4901
  if (elRef.current) elRef.current.textContent = idleDisplay || "";
4699
- setEditing(false);
4700
4902
  setFocused(false);
4701
4903
  event.currentTarget.blur();
4702
4904
  }
@@ -4710,8 +4912,7 @@ function ComposerInlineField({
4710
4912
  // Do not force `inline` — that overrides Tailwind `block` and parks
4711
4913
  // an empty-field hint on the same line as a sibling that has a value.
4712
4914
  opacity: showHint ? 0.5 : void 0
4713
- },
4714
- children: showRendered ? render(value) : null
4915
+ }
4715
4916
  }
4716
4917
  );
4717
4918
  }
@@ -4722,7 +4923,8 @@ function ComposerInlineHtml({
4722
4923
  className,
4723
4924
  Tag = "div",
4724
4925
  layoutNodeId,
4725
- componentId
4926
+ componentId,
4927
+ fieldRef
4726
4928
  }) {
4727
4929
  const elRef = React2.useRef(null);
4728
4930
  React2.useEffect(() => {
@@ -4739,7 +4941,8 @@ function ComposerInlineHtml({
4739
4941
  layoutNodeId,
4740
4942
  componentId,
4741
4943
  name,
4742
- value: sourceValue
4944
+ value: sourceValue,
4945
+ fieldRef
4743
4946
  });
4744
4947
  };
4745
4948
  return React2__default.default.createElement(Tag, {
@@ -4748,6 +4951,9 @@ function ComposerInlineHtml({
4748
4951
  "data-amplifyup-field": name,
4749
4952
  "data-amplifyup-field-type": "richtext",
4750
4953
  "data-amplifyup-node-id": layoutNodeId || void 0,
4954
+ "data-amplifyup-ref-provider": fieldRef?.providerId || void 0,
4955
+ "data-amplifyup-ref-entity": fieldRef?.entity || void 0,
4956
+ "data-amplifyup-ref-id": fieldRef?.id || void 0,
4751
4957
  dangerouslySetInnerHTML: { __html: html },
4752
4958
  onMouseDown: (event) => {
4753
4959
  event.stopPropagation();
@@ -4779,6 +4985,40 @@ function formatFieldValue(value) {
4779
4985
  }
4780
4986
  return "";
4781
4987
  }
4988
+ var FIELD_SCALAR_HINT = "Field expects a scalar field. Did you mean <Field field={post.title} />?";
4989
+ function warnNotScalarField(component, field, fieldValue) {
4990
+ if (process.env.NODE_ENV === "production") return false;
4991
+ if (isBrandedFields(field)) {
4992
+ console.error(`[AmplifyUp SDK] ${component}: ${FIELD_SCALAR_HINT}`);
4993
+ return true;
4994
+ }
4995
+ if (isFieldEnvelope(field) && Array.isArray(field.value)) {
4996
+ console.error(`[AmplifyUp SDK] ${component}: ${FIELD_SCALAR_HINT}`);
4997
+ return true;
4998
+ }
4999
+ if (Array.isArray(fieldValue)) {
5000
+ console.error(`[AmplifyUp SDK] ${component}: ${FIELD_SCALAR_HINT}`);
5001
+ return true;
5002
+ }
5003
+ return false;
5004
+ }
5005
+ var warnedReadOnlyFields = /* @__PURE__ */ new Set();
5006
+ function warnReadOnlyRowField(name) {
5007
+ if (process.env.NODE_ENV === "production") return;
5008
+ const key = name || "(unnamed)";
5009
+ if (warnedReadOnlyFields.has(key)) return;
5010
+ warnedReadOnlyFields.add(key);
5011
+ console.warn(
5012
+ `[AmplifyUp SDK] ${key} has no write target; rendered read-only.`
5013
+ );
5014
+ }
5015
+ function canComposerBind(field, ref, editName) {
5016
+ if (isReadOnlyRowField(field) || isFieldEnvelope(field) && field.readOnly) {
5017
+ warnReadOnlyRowField(editName || (isFieldEnvelope(field) ? field.name : ""));
5018
+ return false;
5019
+ }
5020
+ return true;
5021
+ }
4782
5022
  function warnProjectionProps(component, hasField, hasValue, name) {
4783
5023
  if (process.env.NODE_ENV === "production") return;
4784
5024
  if (!hasField && !hasValue && !name) {
@@ -4790,67 +5030,40 @@ function warnProjectionProps(component, hasField, hasValue, name) {
4790
5030
  function hasOwnProp(props, key) {
4791
5031
  return Object.prototype.hasOwnProperty.call(props, key);
4792
5032
  }
4793
- function isLinkListItem(value) {
4794
- return !!value && typeof value === "object" && !Array.isArray(value);
4795
- }
4796
- function renderLinkList(items, className) {
4797
- const links = items.filter(isLinkListItem).filter((item) => {
4798
- const label = typeof item.label === "string" ? item.label.trim() : "";
4799
- const href = typeof item.href === "string" ? item.href.trim() : "";
4800
- return !!(label || href);
4801
- });
4802
- if (links.length === 0) return null;
4803
- return /* @__PURE__ */ jsxRuntime.jsx("span", { className, style: { display: "contents" }, children: links.map((item, index) => {
4804
- const label = typeof item.label === "string" && item.label.trim() ? item.label : typeof item.href === "string" ? item.href : "Link";
4805
- const href = typeof item.href === "string" && item.href.trim() ? item.href : "#";
4806
- const style = typeof item.style === "string" ? item.style.trim() : "";
4807
- return /* @__PURE__ */ jsxRuntime.jsx(
4808
- "a",
4809
- {
4810
- href,
4811
- target: item.openInNewTab ? "_blank" : void 0,
4812
- rel: item.openInNewTab ? "noreferrer" : void 0,
4813
- "data-amplifyup-action-style": style || void 0,
4814
- children: label
4815
- },
4816
- typeof item._key === "string" && item._key ? item._key : `${href}-${index}`
4817
- );
4818
- }) });
4819
- }
4820
5033
  function Field(props) {
4821
- const { field, value, name, className, render } = props;
5034
+ const { field, value, name, className } = props;
4822
5035
  const context = React2.useContext(ComponentContext);
4823
5036
  const composerEdit = useComposerEditMode();
4824
5037
  const hasField = isFieldEnvelope(field);
4825
5038
  const hasValue = hasOwnProp(props, "value");
4826
- const { editName, fieldValue } = useBoundField(field, value, name, "Field");
5039
+ const { editName, fieldValue, ref } = useBoundField(field, value, name, "Field");
4827
5040
  warnProjectionProps("Field", hasField, hasValue, name);
5041
+ if (warnNotScalarField("Field", field, fieldValue)) {
5042
+ return null;
5043
+ }
4828
5044
  if (!hasField && !hasValue && !name) {
4829
5045
  return null;
4830
5046
  }
5047
+ if (isBrandedFields(field) || Array.isArray(fieldValue)) {
5048
+ return null;
5049
+ }
4831
5050
  const empty = isComposerEmptyText(fieldValue);
4832
- if (composerEdit && editName && context && canInlineEdit(editName, fieldValue)) {
5051
+ const bindComposer = composerEdit && editName && context && canInlineEdit(editName, fieldValue) && canComposerBind(field, ref, editName);
5052
+ if (bindComposer) {
4833
5053
  return /* @__PURE__ */ jsxRuntime.jsx(
4834
5054
  ComposerInlineField,
4835
5055
  {
4836
5056
  name: editName,
4837
5057
  value: fieldValue,
4838
5058
  className,
4839
- render: empty ? void 0 : render,
4840
5059
  layoutNodeId: context.layoutNodeId,
4841
5060
  componentId: context.componentId,
5061
+ fieldRef: ref,
4842
5062
  rich: looksLikeRichCanvasField(editName)
4843
5063
  }
4844
5064
  );
4845
5065
  }
4846
5066
  if (empty) return null;
4847
- if (render) {
4848
- return /* @__PURE__ */ jsxRuntime.jsx("span", { className, style: { display: "contents" }, children: render(fieldValue) });
4849
- }
4850
- if (Array.isArray(fieldValue)) {
4851
- const list = renderLinkList(fieldValue, className);
4852
- if (list) return list;
4853
- }
4854
5067
  const text = formatFieldValue(fieldValue);
4855
5068
  if (!text) return null;
4856
5069
  return /* @__PURE__ */ jsxRuntime.jsx("span", { className, children: text });
@@ -4878,7 +5091,7 @@ function RichText(props) {
4878
5091
  const hasField = isFieldEnvelope(field);
4879
5092
  const hasValueProp = hasOwnProp(props, "value") || childrenValue !== void 0;
4880
5093
  const boundValue = hasOwnProp(props, "value") ? value : childrenValue !== void 0 ? childrenValue : value;
4881
- const { editName, fieldValue } = useBoundField(
5094
+ const { editName, fieldValue, ref } = useBoundField(
4882
5095
  field,
4883
5096
  boundValue,
4884
5097
  name,
@@ -4888,7 +5101,10 @@ function RichText(props) {
4888
5101
  return null;
4889
5102
  }
4890
5103
  warnProjectionProps("RichText", hasField, hasValueProp, name);
4891
- const canEdit = !!context && canInlineEditRichText(editName, fieldValue);
5104
+ if (warnNotScalarField("RichText", field, fieldValue)) {
5105
+ return null;
5106
+ }
5107
+ const canEdit = !!context && canInlineEditRichText(editName, fieldValue) && canComposerBind(field, ref, editName);
4892
5108
  if (isComposerEmptyText(fieldValue)) {
4893
5109
  if (composerEdit && canEdit) {
4894
5110
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -4899,6 +5115,7 @@ function RichText(props) {
4899
5115
  className,
4900
5116
  layoutNodeId: context?.layoutNodeId,
4901
5117
  componentId: context?.componentId,
5118
+ fieldRef: ref,
4902
5119
  rich: true
4903
5120
  }
4904
5121
  );
@@ -4930,7 +5147,8 @@ function RichText(props) {
4930
5147
  className,
4931
5148
  Tag,
4932
5149
  layoutNodeId: context?.layoutNodeId,
4933
- componentId: context?.componentId
5150
+ componentId: context?.componentId,
5151
+ fieldRef: ref
4934
5152
  }
4935
5153
  );
4936
5154
  }
@@ -4960,9 +5178,12 @@ function Image(props) {
4960
5178
  const context = React2.useContext(ComponentContext);
4961
5179
  const hasField = isFieldEnvelope(field);
4962
5180
  const hasValue = hasOwnProp(props, "value");
4963
- const { editName, fieldValue } = useBoundField(field, value, name, "Image");
5181
+ const { editName, fieldValue, ref } = useBoundField(field, value, name, "Image");
4964
5182
  const composerEdit = useComposerEditMode();
4965
5183
  warnProjectionProps("Image", hasField, hasValue, name);
5184
+ if (warnNotScalarField("Image", field, fieldValue)) {
5185
+ return null;
5186
+ }
4966
5187
  if (!hasField && !hasValue && !name) {
4967
5188
  return null;
4968
5189
  }
@@ -4971,10 +5192,13 @@ function Image(props) {
4971
5192
  const alt = altProp ?? portable?.alt ?? "";
4972
5193
  const width = widthProp ?? portable?.width;
4973
5194
  const height = heightProp ?? portable?.height;
4974
- const fieldAttrs = composerEdit && editName ? {
5195
+ const fieldAttrs = composerEdit && editName && canComposerBind(field, ref, editName) ? {
4975
5196
  "data-amplifyup-field": editName,
4976
5197
  "data-amplifyup-field-type": "image",
4977
- "data-amplifyup-node-id": context?.layoutNodeId || void 0
5198
+ "data-amplifyup-node-id": context?.layoutNodeId || void 0,
5199
+ "data-amplifyup-ref-provider": ref?.providerId || void 0,
5200
+ "data-amplifyup-ref-entity": ref?.entity || void 0,
5201
+ "data-amplifyup-ref-id": ref?.id || void 0
4978
5202
  } : null;
4979
5203
  if (composerEdit && !editName && (hasField || hasValue)) {
4980
5204
  console.warn(
@@ -5255,11 +5479,16 @@ exports.QueryContentError = QueryContentError;
5255
5479
  exports.RichText = RichText;
5256
5480
  exports.SelectVariantsError = SelectVariantsError;
5257
5481
  exports.Slot = Slot;
5482
+ exports.attachFieldEnvelopes = attachFieldEnvelopes;
5483
+ exports.composerStoreKey = composerStoreKey;
5484
+ exports.envelopeListRows = envelopeListRows;
5258
5485
  exports.isBrandedFields = isBrandedFields;
5259
5486
  exports.isComposerPreview = isComposerPreview;
5260
5487
  exports.isFieldEnvelope = isFieldEnvelope;
5261
5488
  exports.isPreviewRequest = isPreviewRequest;
5489
+ exports.isReadOnlyRowField = isReadOnlyRowField;
5262
5490
  exports.isWorkingContentRequest = isWorkingContentRequest;
5491
+ exports.listOwnerFromSpec = listOwnerFromSpec;
5263
5492
  exports.nextPageSpec = nextPageSpec;
5264
5493
  exports.queryContent = queryContent;
5265
5494
  exports.searchSpec = searchSpec;