@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.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import React2, { createContext, memo, useState, useEffect, Fragment as Fragment$1, useContext, Component, useMemo, useRef, useSyncExternalStore, useCallback } from 'react';
2
+ import React2, { createContext, memo, useState, useEffect, Fragment as Fragment$1, useContext, useRef, Component, useMemo, useSyncExternalStore, useCallback } from 'react';
3
3
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
4
4
  import { marked } from 'marked';
5
5
 
@@ -407,6 +407,16 @@ function isComposerPreview() {
407
407
 
408
408
  // src/field-envelope.ts
409
409
  var FIELDS_BRAND = Symbol("amplifyup.fields");
410
+ var IDENTIFIER_KEYS = /* @__PURE__ */ new Set([
411
+ "id",
412
+ "_id",
413
+ "slug",
414
+ "key",
415
+ "_key",
416
+ "docId",
417
+ "_type",
418
+ "type"
419
+ ]);
410
420
  function isBrandedFields(value) {
411
421
  return !!value && typeof value === "object" && FIELDS_BRAND in value;
412
422
  }
@@ -428,6 +438,79 @@ function isPortableImageShape(value) {
428
438
  if (!value || typeof value !== "object" || Array.isArray(value)) return false;
429
439
  return "url" in value;
430
440
  }
441
+ function isIdentifierKey(key) {
442
+ return IDENTIFIER_KEYS.has(key);
443
+ }
444
+ function isRecordList(value) {
445
+ if (!Array.isArray(value) || value.length === 0) return false;
446
+ const sample = value.find((item) => item != null);
447
+ if (sample === void 0) return false;
448
+ if (typeof sample !== "object" || Array.isArray(sample)) return false;
449
+ if (isPortableImageShape(sample)) return false;
450
+ if (sample.$$typeof) return false;
451
+ return true;
452
+ }
453
+ function isFieldRef(value) {
454
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
455
+ const rec = value;
456
+ return typeof rec.providerId === "string" && !!rec.providerId && typeof rec.entity === "string" && !!rec.entity && typeof rec.id === "string" && !!rec.id;
457
+ }
458
+ function isListOwner(value) {
459
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
460
+ const rec = value;
461
+ return typeof rec.providerId === "string" && !!rec.providerId && typeof rec.entity === "string" && !!rec.entity;
462
+ }
463
+ function isReadOnlyRowField(value) {
464
+ return isFieldEnvelope(value) && value.readOnly === true && !value.ref;
465
+ }
466
+ function composerStoreKey(name, ref, layoutNodeId) {
467
+ if (isFieldRef(ref)) {
468
+ return `record:${ref.providerId}:${ref.entity}:${ref.id}:${name}`;
469
+ }
470
+ return layoutNodeId ? `page:${layoutNodeId}:${name}` : name;
471
+ }
472
+ function listOwnerFromConnection(conn) {
473
+ if (!conn || typeof conn !== "object") return void 0;
474
+ if (conn.mode === "query") {
475
+ const providerId = String(conn.spec?.providerId || "").trim();
476
+ const entity = String(conn.spec?.entity || "").trim();
477
+ return providerId && entity ? { providerId, entity } : void 0;
478
+ }
479
+ if (conn.mode === "item" || conn.mode === "items") {
480
+ const providerId = String(conn.providerId || "").trim();
481
+ const entity = String(conn.entity || "").trim();
482
+ return providerId && entity ? { providerId, entity } : void 0;
483
+ }
484
+ return void 0;
485
+ }
486
+ function listOwnerFromSpec(spec) {
487
+ const providerId = String(spec?.providerId || "").trim();
488
+ const entity = String(spec?.entity || "").trim();
489
+ return providerId && entity ? { providerId, entity } : void 0;
490
+ }
491
+ function isEnvelopeSources(value) {
492
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
493
+ const rec = value;
494
+ return rec.connections != null || rec.reads != null;
495
+ }
496
+ function normalizeEnvelopeSources(sources) {
497
+ if (!sources) return {};
498
+ if (isEnvelopeSources(sources) && !("mode" in sources)) {
499
+ return sources;
500
+ }
501
+ return { connections: sources };
502
+ }
503
+ function listOwnerForField(fieldName, props, sources) {
504
+ const { connections, reads } = normalizeEnvelopeSources(sources);
505
+ const resourceName = reads?.[fieldName]?.resource || fieldName;
506
+ const fromConn = listOwnerFromConnection(connections?.[resourceName]);
507
+ if (fromConn) return fromConn;
508
+ const paging = props?.[`${fieldName}Pagination`];
509
+ if (paging && typeof paging === "object" && !Array.isArray(paging)) {
510
+ return listOwnerFromSpec(paging.spec);
511
+ }
512
+ return void 0;
513
+ }
431
514
  function joinPath(prefix, key) {
432
515
  return prefix ? `${prefix}.${key}` : key;
433
516
  }
@@ -435,39 +518,101 @@ function emptyValue(raw) {
435
518
  if (raw === void 0) return null;
436
519
  return raw;
437
520
  }
438
- function toFieldEnvelopes(source, prefix = "") {
521
+ function rowId(raw) {
522
+ const candidates = [raw.id, raw._id, raw.docId, raw.key, raw._key];
523
+ for (const c of candidates) {
524
+ if (typeof c === "string" && c.trim()) return c;
525
+ }
526
+ return "";
527
+ }
528
+ function withLeaf(envelope, scope) {
529
+ if (isFieldRef(scope?.ref)) envelope.ref = scope.ref;
530
+ else if (scope?.readOnly) envelope.readOnly = true;
531
+ return envelope;
532
+ }
533
+ function toFieldEnvelopes(source, prefix = "", scope) {
534
+ const ctx = isFieldRef(scope) ? { ref: scope } : scope || {};
439
535
  const input = source && typeof source === "object" && !Array.isArray(source) ? source : {};
440
536
  if (isBrandedFields(input)) {
441
537
  return input;
442
538
  }
443
539
  const out = {};
444
540
  for (const [key, raw] of Object.entries(input)) {
541
+ if (isIdentifierKey(key) && (typeof raw === "string" || raw == null)) {
542
+ out[key] = raw ?? "";
543
+ continue;
544
+ }
445
545
  const path = joinPath(prefix, key);
446
546
  if (isFieldEnvelope(raw)) {
447
- out[key] = { value: raw.value ?? null, name: raw.name || path };
547
+ const inner = raw.value;
548
+ if (isRecordList(inner)) {
549
+ const owner = ctx.owners?.(key);
550
+ out[key] = {
551
+ value: envelopeListRows(inner, owner),
552
+ name: raw.name || path
553
+ };
554
+ continue;
555
+ }
556
+ out[key] = withLeaf(
557
+ { value: raw.value ?? null, name: raw.name || path },
558
+ raw.ref ? { ref: raw.ref } : ctx
559
+ );
560
+ continue;
561
+ }
562
+ if (isRecordList(raw)) {
563
+ const owner = ctx.owners?.(key);
564
+ out[key] = { value: envelopeListRows(raw, owner), name: path };
448
565
  continue;
449
566
  }
450
567
  if (raw && typeof raw === "object" && !Array.isArray(raw) && !isPortableImageShape(raw) && !raw.$$typeof) {
451
- out[key] = toFieldEnvelopes(raw, path);
568
+ out[key] = toFieldEnvelopes(raw, path, ctx);
452
569
  continue;
453
570
  }
454
- out[key] = { value: emptyValue(raw), name: path };
571
+ out[key] = withLeaf({ value: emptyValue(raw), name: path }, ctx);
455
572
  }
456
573
  return brandFields(out);
457
574
  }
458
- function attachFieldEnvelopes(props) {
575
+ function envelopeListRows(items, owner) {
576
+ return items.map((item) => envelopeListRow(item, owner));
577
+ }
578
+ function envelopeListRow(item, owner) {
579
+ if (isBrandedFields(item) && typeof item.id === "string") {
580
+ return item;
581
+ }
582
+ const raw = item && typeof item === "object" && !Array.isArray(item) ? item : {};
583
+ const id = rowId(raw);
584
+ const ref = isListOwner(owner) && id ? { providerId: owner.providerId, entity: owner.entity, id } : void 0;
585
+ const fields = toFieldEnvelopes(raw, "", {
586
+ ref,
587
+ readOnly: !ref
588
+ });
589
+ const row = fields;
590
+ if (typeof row.id !== "string") {
591
+ row.id = id;
592
+ }
593
+ return row;
594
+ }
595
+ function attachFieldEnvelopes(props, sources) {
459
596
  const raw = props && typeof props === "object" ? { ...props } : {};
460
597
  if (isBrandedFields(raw.fields)) return raw;
461
598
  const { fields: existing, ...content } = raw;
462
599
  const source = existing && typeof existing === "object" && !isFieldEnvelope(existing) ? existing : content;
463
- return { ...raw, fields: toFieldEnvelopes(source) };
600
+ return {
601
+ ...raw,
602
+ fields: toFieldEnvelopes(source, "", {
603
+ owners: (fieldName) => listOwnerForField(fieldName, source, sources)
604
+ })
605
+ };
464
606
  }
465
607
  function walkLayoutNodes(nodes) {
466
608
  if (!Array.isArray(nodes)) return;
467
609
  for (const node of nodes) {
468
610
  if (!node || typeof node !== "object") continue;
469
611
  const rec = node;
470
- rec.props = attachFieldEnvelopes(rec.props);
612
+ rec.props = attachFieldEnvelopes(rec.props, {
613
+ connections: rec.resources,
614
+ reads: rec.reads
615
+ });
471
616
  for (const slot of rec.slots || []) {
472
617
  walkLayoutNodes(slot.children);
473
618
  }
@@ -481,15 +626,36 @@ function envelopePageConfig(page) {
481
626
  }
482
627
  function collectFieldPatches(props) {
483
628
  const out = [];
629
+ const walkRows = (items) => {
630
+ for (const item of items) {
631
+ if (isBrandedFields(item) || item && typeof item === "object" && !Array.isArray(item) && !isFieldEnvelope(item)) {
632
+ walk(item, "");
633
+ }
634
+ }
635
+ };
484
636
  const walk = (obj, prefix) => {
485
637
  for (const [key, raw] of Object.entries(obj)) {
638
+ if (isIdentifierKey(key)) continue;
486
639
  if (key === "fields" && raw && typeof raw === "object" && !Array.isArray(raw) && !isFieldEnvelope(raw)) {
487
640
  walk(raw, prefix);
488
641
  continue;
489
642
  }
490
643
  const path = joinPath(prefix, key);
491
644
  if (isFieldEnvelope(raw)) {
492
- out.push({ name: raw.name || path, value: raw.value });
645
+ if (isRecordList(raw.value)) {
646
+ walkRows(raw.value);
647
+ continue;
648
+ }
649
+ const patch = {
650
+ name: raw.name || path,
651
+ value: raw.value
652
+ };
653
+ if (raw.ref) patch.ref = raw.ref;
654
+ out.push(patch);
655
+ continue;
656
+ }
657
+ if (isRecordList(raw)) {
658
+ walkRows(raw);
493
659
  continue;
494
660
  }
495
661
  if (raw && typeof raw === "object" && !Array.isArray(raw) && !isPortableImageShape(raw) && !raw.$$typeof) {
@@ -506,7 +672,12 @@ function collectFieldPatches(props) {
506
672
  }
507
673
  function resolveEditableBinding(field, value, name) {
508
674
  if (isFieldEnvelope(field)) {
509
- return { name: field.name, value: field.value, requiresName: false };
675
+ return {
676
+ name: field.name,
677
+ value: field.value,
678
+ ref: field.ref,
679
+ requiresName: false
680
+ };
510
681
  }
511
682
  return {
512
683
  name: name || "",
@@ -865,7 +1036,10 @@ async function fetchEdgeResolve(options) {
865
1036
  return envelopeResolvedPayload(body);
866
1037
  }
867
1038
  function envelopeResolvedComponent(node) {
868
- node.props = attachFieldEnvelopes(node.props);
1039
+ node.props = attachFieldEnvelopes(node.props, {
1040
+ connections: node.resources,
1041
+ reads: node.reads
1042
+ });
869
1043
  if (!node.children) return;
870
1044
  for (const kids of Object.values(node.children)) {
871
1045
  for (const child of kids || []) envelopeResolvedComponent(child);
@@ -1124,7 +1298,7 @@ async function fetchEdgeQuery(options) {
1124
1298
  async function queryContent(options) {
1125
1299
  const target = resolveAmplifyUpTarget({ configTarget: options.target });
1126
1300
  const { edgeUrl } = resolveAmplifyUpUrls(target);
1127
- return fetchEdgeQuery({
1301
+ const raw = await fetchEdgeQuery({
1128
1302
  edgeUrl,
1129
1303
  trackingId: options.trackingId,
1130
1304
  route: options.route,
@@ -1133,6 +1307,13 @@ async function queryContent(options) {
1133
1307
  fetch: options.fetch,
1134
1308
  signal: options.signal
1135
1309
  });
1310
+ return {
1311
+ ...raw,
1312
+ results: envelopeListRows(
1313
+ raw.results,
1314
+ listOwnerFromSpec(options.spec)
1315
+ )
1316
+ };
1136
1317
  }
1137
1318
  function nextPageSpec(pagination) {
1138
1319
  return { ...pagination.spec, offset: pagination.nextOffset };
@@ -3617,39 +3798,62 @@ var ComposerFieldStore = class {
3617
3798
  if (set.size === 0) this.listeners.delete(name);
3618
3799
  };
3619
3800
  }
3801
+ keys() {
3802
+ return [...this.values.keys()];
3803
+ }
3804
+ delete(name) {
3805
+ if (!name || !this.values.has(name)) return;
3806
+ this.values.delete(name);
3807
+ const set = this.listeners.get(name);
3808
+ if (!set) return;
3809
+ for (const fn of set) fn();
3810
+ }
3620
3811
  };
3621
3812
  var ComposerStoreContext = createContext(null);
3622
- function matchesNode(eventNodeId, layoutNodeId) {
3623
- if (eventNodeId && layoutNodeId && String(eventNodeId) !== String(layoutNodeId)) {
3624
- return false;
3625
- }
3626
- return true;
3813
+ var ComposerNodeContext = createContext(void 0);
3814
+ function applyComposerPatch(store, name, value, ref, layoutNodeId) {
3815
+ store.set(composerStoreKey(name, ref, layoutNodeId), value);
3627
3816
  }
3628
3817
  function ComposerProvider({
3629
- layoutNodeId,
3630
3818
  children
3631
3819
  }) {
3820
+ const existing = useContext(ComposerStoreContext);
3632
3821
  const storeRef = useRef(null);
3633
3822
  if (!storeRef.current) storeRef.current = new ComposerFieldStore();
3634
- const store = storeRef.current;
3823
+ const store = existing || storeRef.current;
3635
3824
  useEffect(() => {
3636
- const applyField = (fieldName, value, nodeId) => {
3825
+ if (existing) return;
3826
+ const applyField = (fieldName, value, nodeId, ref) => {
3637
3827
  if (!fieldName || typeof fieldName !== "string") return;
3638
- if (!matchesNode(nodeId, layoutNodeId)) return;
3639
- store.set(fieldName, value);
3828
+ const fieldRef = isFieldRef(ref) ? ref : void 0;
3829
+ const layoutNodeId = typeof nodeId === "string" && nodeId ? nodeId : void 0;
3830
+ applyComposerPatch(store, fieldName, value, fieldRef, layoutNodeId);
3640
3831
  };
3641
3832
  const applyProps = (nextProps, nodeId) => {
3642
3833
  if (!nextProps || typeof nextProps !== "object" || Array.isArray(nextProps)) {
3643
3834
  return;
3644
3835
  }
3645
- if (!matchesNode(nodeId, layoutNodeId)) return;
3646
- for (const patch of collectFieldPatches(nextProps)) {
3647
- store.set(patch.name, patch.value);
3836
+ const layoutNodeId = typeof nodeId === "string" && nodeId ? nodeId : void 0;
3837
+ for (const patch of collectFieldPatches(
3838
+ nextProps
3839
+ )) {
3840
+ applyComposerPatch(
3841
+ store,
3842
+ patch.name,
3843
+ patch.value,
3844
+ patch.ref,
3845
+ patch.ref ? void 0 : layoutNodeId
3846
+ );
3648
3847
  }
3649
3848
  };
3650
3849
  const onPatch = (event) => {
3651
3850
  const detail = event.detail || {};
3652
- applyField(detail.fieldName, detail.value, detail.layoutNodeId);
3851
+ applyField(
3852
+ detail.fieldName,
3853
+ detail.value,
3854
+ detail.layoutNodeId,
3855
+ detail.ref
3856
+ );
3653
3857
  };
3654
3858
  const onPropsPatch = (event) => {
3655
3859
  const detail = event.detail || {};
@@ -3661,7 +3865,12 @@ function ComposerProvider({
3661
3865
  return;
3662
3866
  }
3663
3867
  if (event.data?.type !== "AMPLIFYUP_FIELD_PATCH") return;
3664
- applyField(event.data.fieldName, event.data.value, event.data.layoutNodeId);
3868
+ applyField(
3869
+ event.data.fieldName,
3870
+ event.data.value,
3871
+ event.data.layoutNodeId,
3872
+ event.data.ref
3873
+ );
3665
3874
  };
3666
3875
  window.addEventListener("amplifyup:field-patch", onPatch);
3667
3876
  window.addEventListener("amplifyup:props-patch", onPropsPatch);
@@ -3671,23 +3880,26 @@ function ComposerProvider({
3671
3880
  window.removeEventListener("amplifyup:props-patch", onPropsPatch);
3672
3881
  window.removeEventListener("message", onMessage);
3673
3882
  };
3674
- }, [layoutNodeId, store]);
3883
+ }, [existing, store]);
3884
+ if (existing) return /* @__PURE__ */ jsx(Fragment, { children });
3675
3885
  return /* @__PURE__ */ jsx(ComposerStoreContext.Provider, { value: store, children });
3676
3886
  }
3677
- function useComposerFieldValue(name, fallback) {
3887
+ function useComposerFieldValue(name, fallback, ref) {
3678
3888
  const store = useContext(ComposerStoreContext);
3889
+ const layoutNodeId = useContext(ComposerNodeContext);
3890
+ const key = composerStoreKey(name, ref, layoutNodeId);
3679
3891
  const subscribe = useCallback(
3680
3892
  (onStoreChange) => {
3681
3893
  if (!store || !name) return () => {
3682
3894
  };
3683
- return store.subscribe(name, onStoreChange);
3895
+ return store.subscribe(key, onStoreChange);
3684
3896
  },
3685
- [store, name]
3897
+ [store, name, key]
3686
3898
  );
3687
3899
  const getSnapshot = useCallback(() => {
3688
3900
  if (!store || !name) return void 0;
3689
- return store.get(name);
3690
- }, [store, name]);
3901
+ return store.get(key);
3902
+ }, [store, name, key]);
3691
3903
  const overlay = useSyncExternalStore(subscribe, getSnapshot, () => void 0);
3692
3904
  return overlay !== void 0 ? overlay : fallback;
3693
3905
  }
@@ -3698,7 +3910,7 @@ function MaybeComposerProvider({
3698
3910
  }) {
3699
3911
  const content = useMemo(() => children, [children]);
3700
3912
  if (!enabled) return /* @__PURE__ */ jsx(Fragment, { children: content });
3701
- return /* @__PURE__ */ jsx(ComposerProvider, { layoutNodeId, children });
3913
+ return /* @__PURE__ */ jsx(ComposerProvider, { children: /* @__PURE__ */ jsx(ComposerNodeContext.Provider, { value: layoutNodeId, children }) });
3702
3914
  }
3703
3915
  function nodeRenderProps(node) {
3704
3916
  const settings = node.settings || {};
@@ -4156,7 +4368,7 @@ function AmplifyRendererInner({
4156
4368
  if (layoutTree.length === 0) {
4157
4369
  return /* @__PURE__ */ jsx("main", { children: emptyComponent || /* @__PURE__ */ jsx("div", { className: "container mx-auto px-4 py-16", children: /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: "No content configured for this page." }) }) });
4158
4370
  }
4159
- return /* @__PURE__ */ jsx("main", { children: composerPreview || isComposerPreview() ? /* @__PURE__ */ jsx(
4371
+ return /* @__PURE__ */ jsx(ComposerProvider, { children: /* @__PURE__ */ jsx("main", { children: composerPreview || isComposerPreview() ? /* @__PURE__ */ jsx(
4160
4372
  "div",
4161
4373
  {
4162
4374
  "data-slot-id": "main",
@@ -4165,7 +4377,7 @@ function AmplifyRendererInner({
4165
4377
  "data-slot-empty": layoutTree.length === 0 ? "true" : void 0,
4166
4378
  children: layoutTree.map((node) => /* @__PURE__ */ jsx(Fragment$1, { children: renderNode(node) }, node.id))
4167
4379
  }
4168
- ) : layoutTree.map((node) => /* @__PURE__ */ jsx(Fragment$1, { children: renderNode(node) }, node.id)) });
4380
+ ) : layoutTree.map((node) => /* @__PURE__ */ jsx(Fragment$1, { children: renderNode(node) }, node.id)) }) });
4169
4381
  }
4170
4382
  var AmplifyRenderer = memo(AmplifyRendererInner);
4171
4383
  function AddComponentIcon({ size = 28 }) {
@@ -4354,6 +4566,21 @@ function AmplifyPageContent({
4354
4566
  }
4355
4567
  );
4356
4568
  }
4569
+
4570
+ // src/composer-edit-mode.ts
4571
+ function isComposerEditMode() {
4572
+ if (typeof window === "undefined") return false;
4573
+ return isComposerPreview() && window.__AMPLIFYUP_EVENT_SELECTION__ !== true;
4574
+ }
4575
+ function subscribeComposerEdit(onStoreChange) {
4576
+ if (typeof window === "undefined") return () => {
4577
+ };
4578
+ window.addEventListener("amplifyup:composer-edit", onStoreChange);
4579
+ return () => window.removeEventListener("amplifyup:composer-edit", onStoreChange);
4580
+ }
4581
+ function getComposerEditModeServer() {
4582
+ return false;
4583
+ }
4357
4584
  var ComponentContext = createContext(null);
4358
4585
  function ComponentContextProvider({
4359
4586
  children,
@@ -4455,10 +4682,6 @@ function Slot({
4455
4682
  }
4456
4683
  );
4457
4684
  }
4458
- function isComposerEditMode() {
4459
- if (typeof window === "undefined") return false;
4460
- return isComposerPreview() && window.__AMPLIFYUP_EVENT_SELECTION__ !== true;
4461
- }
4462
4685
  function isLikelyNonTextFieldName(name) {
4463
4686
  const n = name.toLowerCase();
4464
4687
  return n.includes("href") || n.includes("url") || n.includes("src") || n.includes("image") || n.includes("icon") || n.includes("overlay") || n.includes("color");
@@ -4493,17 +4716,11 @@ function canInlineEditRichText(name, value) {
4493
4716
  }
4494
4717
  return true;
4495
4718
  }
4496
- function subscribeComposerEdit(onStoreChange) {
4497
- if (typeof window === "undefined") return () => {
4498
- };
4499
- window.addEventListener("amplifyup:composer-edit", onStoreChange);
4500
- return () => window.removeEventListener("amplifyup:composer-edit", onStoreChange);
4501
- }
4502
4719
  function useComposerEditMode() {
4503
4720
  return useSyncExternalStore(
4504
4721
  subscribeComposerEdit,
4505
4722
  isComposerEditMode,
4506
- () => false
4723
+ getComposerEditModeServer
4507
4724
  );
4508
4725
  }
4509
4726
  function useBoundField(field, value, name, component) {
@@ -4513,10 +4730,10 @@ function useBoundField(field, value, name, component) {
4513
4730
  `[AmplifyUp SDK] ${component} value={\u2026} requires name="\u2026" for computed values`
4514
4731
  );
4515
4732
  }
4516
- const fieldValue = useComposerFieldValue(bound.name, bound.value);
4517
- return { editName: bound.name, fieldValue };
4733
+ const fieldValue = useComposerFieldValue(bound.name, bound.value, bound.ref);
4734
+ return { editName: bound.name, fieldValue, ref: bound.ref };
4518
4735
  }
4519
- function commitComposerField(layoutNodeId, componentId, name, value) {
4736
+ function commitComposerField(layoutNodeId, componentId, name, value, ref) {
4520
4737
  if (typeof window === "undefined" || window.parent === window) return;
4521
4738
  window.parent.postMessage(
4522
4739
  {
@@ -4524,7 +4741,8 @@ function commitComposerField(layoutNodeId, componentId, name, value) {
4524
4741
  layoutNodeId,
4525
4742
  componentId,
4526
4743
  fieldName: name,
4527
- value
4744
+ value,
4745
+ ...ref ? { ref } : {}
4528
4746
  },
4529
4747
  "*"
4530
4748
  );
@@ -4549,6 +4767,7 @@ function requestCanvasRichTextEdit(opts) {
4549
4767
  componentId: opts.componentId,
4550
4768
  fieldName: opts.name,
4551
4769
  value: opts.value,
4770
+ ...opts.fieldRef ? { ref: opts.fieldRef } : {},
4552
4771
  bounds: {
4553
4772
  top: rect.top,
4554
4773
  left: rect.left,
@@ -4571,23 +4790,21 @@ function ComposerInlineField({
4571
4790
  name,
4572
4791
  value,
4573
4792
  className,
4574
- render,
4575
4793
  layoutNodeId,
4576
4794
  componentId,
4795
+ fieldRef,
4577
4796
  rich = false
4578
4797
  }) {
4579
- const [editing, setEditing] = useState(false);
4580
4798
  const [focused, setFocused] = useState(false);
4581
4799
  const elRef = useRef(null);
4582
4800
  const storedEmpty = isComposerEmptyText(value);
4583
4801
  const text = storedEmpty ? "" : formatFieldValue(value);
4584
4802
  const hint = COMPOSER_EMPTY_FIELD_HINT;
4585
4803
  const idleDisplay = storedEmpty ? hint : text;
4586
- const showRendered = !!render && !editing && !storedEmpty;
4587
- const showHint = storedEmpty && !focused && !showRendered;
4804
+ const showHint = storedEmpty && !focused;
4588
4805
  useEffect(() => {
4589
4806
  const el = elRef.current;
4590
- if (!el || showRendered) return;
4807
+ if (!el) return;
4591
4808
  if (document.activeElement === el) return;
4592
4809
  if (el.querySelector(
4593
4810
  "input, button, select, textarea, form, svg, iframe, img"
@@ -4596,34 +4813,20 @@ function ComposerInlineField({
4596
4813
  }
4597
4814
  const next = idleDisplay || "";
4598
4815
  if (el.textContent !== next) el.textContent = next;
4599
- }, [idleDisplay, showRendered]);
4600
- useEffect(() => {
4601
- if (!editing || !elRef.current) return;
4602
- const el = elRef.current;
4603
- if (storedEmpty) {
4604
- el.textContent = "";
4605
- el.focus();
4606
- placeCaret(el, true);
4607
- return;
4608
- }
4609
- el.textContent = idleDisplay || "";
4610
- el.focus();
4611
- placeCaret(el, false);
4612
- }, [editing, storedEmpty, idleDisplay]);
4816
+ }, [idleDisplay]);
4613
4817
  const finishEdit = () => {
4614
4818
  const raw = (elRef.current?.innerText ?? "").replace(/\u00a0/g, " ").replace(/\n+$/g, "");
4615
4819
  const next = raw.trim() === "" ? "" : raw;
4616
- setEditing(false);
4617
4820
  setFocused(false);
4618
4821
  if (storedEmpty && next === "") {
4619
4822
  if (elRef.current) elRef.current.textContent = hint;
4620
4823
  if (typeof value === "string" && EMPTY_FIELD_PLACEHOLDERS.has(value.trim())) {
4621
- commitComposerField(layoutNodeId, componentId, name, "");
4824
+ commitComposerField(layoutNodeId, componentId, name, "", fieldRef);
4622
4825
  }
4623
4826
  return;
4624
4827
  }
4625
4828
  if (next === text) return;
4626
- commitComposerField(layoutNodeId, componentId, name, next);
4829
+ commitComposerField(layoutNodeId, componentId, name, next, fieldRef);
4627
4830
  };
4628
4831
  const openRichEditor = (event) => {
4629
4832
  if (!isComposerEditMode() || !elRef.current) return;
@@ -4635,7 +4838,8 @@ function ComposerInlineField({
4635
4838
  layoutNodeId,
4636
4839
  componentId,
4637
4840
  name,
4638
- value: source
4841
+ value: source,
4842
+ fieldRef
4639
4843
  });
4640
4844
  };
4641
4845
  return /* @__PURE__ */ jsx(
@@ -4646,8 +4850,11 @@ function ComposerInlineField({
4646
4850
  "data-amplifyup-field": name,
4647
4851
  "data-amplifyup-field-type": rich ? "richtext" : "text",
4648
4852
  "data-amplifyup-node-id": layoutNodeId || void 0,
4853
+ "data-amplifyup-ref-provider": fieldRef?.providerId || void 0,
4854
+ "data-amplifyup-ref-entity": fieldRef?.entity || void 0,
4855
+ "data-amplifyup-ref-id": fieldRef?.id || void 0,
4649
4856
  "data-amplifyup-empty-hint": showHint ? "true" : void 0,
4650
- contentEditable: !rich && !showRendered,
4857
+ contentEditable: !rich,
4651
4858
  suppressContentEditableWarning: true,
4652
4859
  role: "textbox",
4653
4860
  tabIndex: 0,
@@ -4662,9 +4869,6 @@ function ComposerInlineField({
4662
4869
  openRichEditor(event);
4663
4870
  return;
4664
4871
  }
4665
- if (render) {
4666
- setEditing(true);
4667
- }
4668
4872
  },
4669
4873
  onFocus: () => {
4670
4874
  if (!isComposerEditMode()) return;
@@ -4678,7 +4882,6 @@ function ComposerInlineField({
4678
4882
  el.textContent = "";
4679
4883
  placeCaret(el, true);
4680
4884
  }
4681
- if (render) setEditing(true);
4682
4885
  },
4683
4886
  onBlur: rich ? void 0 : finishEdit,
4684
4887
  onKeyDown: (event) => {
@@ -4690,7 +4893,6 @@ function ComposerInlineField({
4690
4893
  if (event.key === "Escape") {
4691
4894
  event.preventDefault();
4692
4895
  if (elRef.current) elRef.current.textContent = idleDisplay || "";
4693
- setEditing(false);
4694
4896
  setFocused(false);
4695
4897
  event.currentTarget.blur();
4696
4898
  }
@@ -4704,8 +4906,7 @@ function ComposerInlineField({
4704
4906
  // Do not force `inline` — that overrides Tailwind `block` and parks
4705
4907
  // an empty-field hint on the same line as a sibling that has a value.
4706
4908
  opacity: showHint ? 0.5 : void 0
4707
- },
4708
- children: showRendered ? render(value) : null
4909
+ }
4709
4910
  }
4710
4911
  );
4711
4912
  }
@@ -4716,7 +4917,8 @@ function ComposerInlineHtml({
4716
4917
  className,
4717
4918
  Tag = "div",
4718
4919
  layoutNodeId,
4719
- componentId
4920
+ componentId,
4921
+ fieldRef
4720
4922
  }) {
4721
4923
  const elRef = useRef(null);
4722
4924
  useEffect(() => {
@@ -4733,7 +4935,8 @@ function ComposerInlineHtml({
4733
4935
  layoutNodeId,
4734
4936
  componentId,
4735
4937
  name,
4736
- value: sourceValue
4938
+ value: sourceValue,
4939
+ fieldRef
4737
4940
  });
4738
4941
  };
4739
4942
  return React2.createElement(Tag, {
@@ -4742,6 +4945,9 @@ function ComposerInlineHtml({
4742
4945
  "data-amplifyup-field": name,
4743
4946
  "data-amplifyup-field-type": "richtext",
4744
4947
  "data-amplifyup-node-id": layoutNodeId || void 0,
4948
+ "data-amplifyup-ref-provider": fieldRef?.providerId || void 0,
4949
+ "data-amplifyup-ref-entity": fieldRef?.entity || void 0,
4950
+ "data-amplifyup-ref-id": fieldRef?.id || void 0,
4745
4951
  dangerouslySetInnerHTML: { __html: html },
4746
4952
  onMouseDown: (event) => {
4747
4953
  event.stopPropagation();
@@ -4773,6 +4979,40 @@ function formatFieldValue(value) {
4773
4979
  }
4774
4980
  return "";
4775
4981
  }
4982
+ var FIELD_SCALAR_HINT = "Field expects a scalar field. Did you mean <Field field={post.title} />?";
4983
+ function warnNotScalarField(component, field, fieldValue) {
4984
+ if (process.env.NODE_ENV === "production") return false;
4985
+ if (isBrandedFields(field)) {
4986
+ console.error(`[AmplifyUp SDK] ${component}: ${FIELD_SCALAR_HINT}`);
4987
+ return true;
4988
+ }
4989
+ if (isFieldEnvelope(field) && Array.isArray(field.value)) {
4990
+ console.error(`[AmplifyUp SDK] ${component}: ${FIELD_SCALAR_HINT}`);
4991
+ return true;
4992
+ }
4993
+ if (Array.isArray(fieldValue)) {
4994
+ console.error(`[AmplifyUp SDK] ${component}: ${FIELD_SCALAR_HINT}`);
4995
+ return true;
4996
+ }
4997
+ return false;
4998
+ }
4999
+ var warnedReadOnlyFields = /* @__PURE__ */ new Set();
5000
+ function warnReadOnlyRowField(name) {
5001
+ if (process.env.NODE_ENV === "production") return;
5002
+ const key = name || "(unnamed)";
5003
+ if (warnedReadOnlyFields.has(key)) return;
5004
+ warnedReadOnlyFields.add(key);
5005
+ console.warn(
5006
+ `[AmplifyUp SDK] ${key} has no write target; rendered read-only.`
5007
+ );
5008
+ }
5009
+ function canComposerBind(field, ref, editName) {
5010
+ if (isReadOnlyRowField(field) || isFieldEnvelope(field) && field.readOnly) {
5011
+ warnReadOnlyRowField(editName || (isFieldEnvelope(field) ? field.name : ""));
5012
+ return false;
5013
+ }
5014
+ return true;
5015
+ }
4776
5016
  function warnProjectionProps(component, hasField, hasValue, name) {
4777
5017
  if (process.env.NODE_ENV === "production") return;
4778
5018
  if (!hasField && !hasValue && !name) {
@@ -4784,67 +5024,40 @@ function warnProjectionProps(component, hasField, hasValue, name) {
4784
5024
  function hasOwnProp(props, key) {
4785
5025
  return Object.prototype.hasOwnProperty.call(props, key);
4786
5026
  }
4787
- function isLinkListItem(value) {
4788
- return !!value && typeof value === "object" && !Array.isArray(value);
4789
- }
4790
- function renderLinkList(items, className) {
4791
- const links = items.filter(isLinkListItem).filter((item) => {
4792
- const label = typeof item.label === "string" ? item.label.trim() : "";
4793
- const href = typeof item.href === "string" ? item.href.trim() : "";
4794
- return !!(label || href);
4795
- });
4796
- if (links.length === 0) return null;
4797
- return /* @__PURE__ */ jsx("span", { className, style: { display: "contents" }, children: links.map((item, index) => {
4798
- const label = typeof item.label === "string" && item.label.trim() ? item.label : typeof item.href === "string" ? item.href : "Link";
4799
- const href = typeof item.href === "string" && item.href.trim() ? item.href : "#";
4800
- const style = typeof item.style === "string" ? item.style.trim() : "";
4801
- return /* @__PURE__ */ jsx(
4802
- "a",
4803
- {
4804
- href,
4805
- target: item.openInNewTab ? "_blank" : void 0,
4806
- rel: item.openInNewTab ? "noreferrer" : void 0,
4807
- "data-amplifyup-action-style": style || void 0,
4808
- children: label
4809
- },
4810
- typeof item._key === "string" && item._key ? item._key : `${href}-${index}`
4811
- );
4812
- }) });
4813
- }
4814
5027
  function Field(props) {
4815
- const { field, value, name, className, render } = props;
5028
+ const { field, value, name, className } = props;
4816
5029
  const context = useContext(ComponentContext);
4817
5030
  const composerEdit = useComposerEditMode();
4818
5031
  const hasField = isFieldEnvelope(field);
4819
5032
  const hasValue = hasOwnProp(props, "value");
4820
- const { editName, fieldValue } = useBoundField(field, value, name, "Field");
5033
+ const { editName, fieldValue, ref } = useBoundField(field, value, name, "Field");
4821
5034
  warnProjectionProps("Field", hasField, hasValue, name);
5035
+ if (warnNotScalarField("Field", field, fieldValue)) {
5036
+ return null;
5037
+ }
4822
5038
  if (!hasField && !hasValue && !name) {
4823
5039
  return null;
4824
5040
  }
5041
+ if (isBrandedFields(field) || Array.isArray(fieldValue)) {
5042
+ return null;
5043
+ }
4825
5044
  const empty = isComposerEmptyText(fieldValue);
4826
- if (composerEdit && editName && context && canInlineEdit(editName, fieldValue)) {
5045
+ const bindComposer = composerEdit && editName && context && canInlineEdit(editName, fieldValue) && canComposerBind(field, ref, editName);
5046
+ if (bindComposer) {
4827
5047
  return /* @__PURE__ */ jsx(
4828
5048
  ComposerInlineField,
4829
5049
  {
4830
5050
  name: editName,
4831
5051
  value: fieldValue,
4832
5052
  className,
4833
- render: empty ? void 0 : render,
4834
5053
  layoutNodeId: context.layoutNodeId,
4835
5054
  componentId: context.componentId,
5055
+ fieldRef: ref,
4836
5056
  rich: looksLikeRichCanvasField(editName)
4837
5057
  }
4838
5058
  );
4839
5059
  }
4840
5060
  if (empty) return null;
4841
- if (render) {
4842
- return /* @__PURE__ */ jsx("span", { className, style: { display: "contents" }, children: render(fieldValue) });
4843
- }
4844
- if (Array.isArray(fieldValue)) {
4845
- const list = renderLinkList(fieldValue, className);
4846
- if (list) return list;
4847
- }
4848
5061
  const text = formatFieldValue(fieldValue);
4849
5062
  if (!text) return null;
4850
5063
  return /* @__PURE__ */ jsx("span", { className, children: text });
@@ -4872,7 +5085,7 @@ function RichText(props) {
4872
5085
  const hasField = isFieldEnvelope(field);
4873
5086
  const hasValueProp = hasOwnProp(props, "value") || childrenValue !== void 0;
4874
5087
  const boundValue = hasOwnProp(props, "value") ? value : childrenValue !== void 0 ? childrenValue : value;
4875
- const { editName, fieldValue } = useBoundField(
5088
+ const { editName, fieldValue, ref } = useBoundField(
4876
5089
  field,
4877
5090
  boundValue,
4878
5091
  name,
@@ -4882,7 +5095,10 @@ function RichText(props) {
4882
5095
  return null;
4883
5096
  }
4884
5097
  warnProjectionProps("RichText", hasField, hasValueProp, name);
4885
- const canEdit = !!context && canInlineEditRichText(editName, fieldValue);
5098
+ if (warnNotScalarField("RichText", field, fieldValue)) {
5099
+ return null;
5100
+ }
5101
+ const canEdit = !!context && canInlineEditRichText(editName, fieldValue) && canComposerBind(field, ref, editName);
4886
5102
  if (isComposerEmptyText(fieldValue)) {
4887
5103
  if (composerEdit && canEdit) {
4888
5104
  return /* @__PURE__ */ jsx(
@@ -4893,6 +5109,7 @@ function RichText(props) {
4893
5109
  className,
4894
5110
  layoutNodeId: context?.layoutNodeId,
4895
5111
  componentId: context?.componentId,
5112
+ fieldRef: ref,
4896
5113
  rich: true
4897
5114
  }
4898
5115
  );
@@ -4924,7 +5141,8 @@ function RichText(props) {
4924
5141
  className,
4925
5142
  Tag,
4926
5143
  layoutNodeId: context?.layoutNodeId,
4927
- componentId: context?.componentId
5144
+ componentId: context?.componentId,
5145
+ fieldRef: ref
4928
5146
  }
4929
5147
  );
4930
5148
  }
@@ -4954,9 +5172,12 @@ function Image(props) {
4954
5172
  const context = useContext(ComponentContext);
4955
5173
  const hasField = isFieldEnvelope(field);
4956
5174
  const hasValue = hasOwnProp(props, "value");
4957
- const { editName, fieldValue } = useBoundField(field, value, name, "Image");
5175
+ const { editName, fieldValue, ref } = useBoundField(field, value, name, "Image");
4958
5176
  const composerEdit = useComposerEditMode();
4959
5177
  warnProjectionProps("Image", hasField, hasValue, name);
5178
+ if (warnNotScalarField("Image", field, fieldValue)) {
5179
+ return null;
5180
+ }
4960
5181
  if (!hasField && !hasValue && !name) {
4961
5182
  return null;
4962
5183
  }
@@ -4965,10 +5186,13 @@ function Image(props) {
4965
5186
  const alt = altProp ?? portable?.alt ?? "";
4966
5187
  const width = widthProp ?? portable?.width;
4967
5188
  const height = heightProp ?? portable?.height;
4968
- const fieldAttrs = composerEdit && editName ? {
5189
+ const fieldAttrs = composerEdit && editName && canComposerBind(field, ref, editName) ? {
4969
5190
  "data-amplifyup-field": editName,
4970
5191
  "data-amplifyup-field-type": "image",
4971
- "data-amplifyup-node-id": context?.layoutNodeId || void 0
5192
+ "data-amplifyup-node-id": context?.layoutNodeId || void 0,
5193
+ "data-amplifyup-ref-provider": ref?.providerId || void 0,
5194
+ "data-amplifyup-ref-entity": ref?.entity || void 0,
5195
+ "data-amplifyup-ref-id": ref?.id || void 0
4972
5196
  } : null;
4973
5197
  if (composerEdit && !editName && (hasField || hasValue)) {
4974
5198
  console.warn(
@@ -5237,6 +5461,6 @@ function useAmplifyUp() {
5237
5461
  return context;
5238
5462
  }
5239
5463
 
5240
- export { AmplifyPageContent, AmplifyRenderer, AmplifyUpProvider, ComponentContextProvider, ComposerProvider, Field, Image, MaybeComposerProvider, QueryContentError, RichText, SelectVariantsError, Slot, isBrandedFields, isComposerPreview, isFieldEnvelope, isPreviewRequest, isWorkingContentRequest, nextPageSpec, queryContent, searchSpec, selectVariants, toFieldEnvelopes, useAmplifyUp };
5464
+ export { AmplifyPageContent, AmplifyRenderer, AmplifyUpProvider, ComponentContextProvider, ComposerProvider, Field, Image, MaybeComposerProvider, QueryContentError, RichText, SelectVariantsError, Slot, attachFieldEnvelopes, composerStoreKey, envelopeListRows, isBrandedFields, isComposerPreview, isFieldEnvelope, isPreviewRequest, isReadOnlyRowField, isWorkingContentRequest, listOwnerFromSpec, nextPageSpec, queryContent, searchSpec, selectVariants, toFieldEnvelopes, useAmplifyUp };
5241
5465
  //# sourceMappingURL=react.mjs.map
5242
5466
  //# sourceMappingURL=react.mjs.map