@amplifyup/sdk 0.1.68 → 0.1.70

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.d.mts CHANGED
@@ -43,6 +43,20 @@ interface AmplifyPageContentProps {
43
43
  */
44
44
  declare function AmplifyPageContent({ fallback, renderComponent, pageConfig: pageConfigProp, forceComposerPreview, previewLoadingComponent, previewEmptyComponent, loadingComponent, emptyComponent, errorComponent, }: AmplifyPageContentProps): react_jsx_runtime.JSX.Element | null;
45
45
 
46
+ /**
47
+ * True when the page is running inside AmplifyUp Composer.
48
+ *
49
+ * Safe to use for conditional render (e.g. expose a CSS-background image
50
+ * as a clickable `<Image>` only in Composer). First client render matches
51
+ * the server (`false`); detection runs after mount.
52
+ *
53
+ * @param force - When true (e.g. SSR already knows `?preview=true`), skip
54
+ * the post-mount flip and return true immediately.
55
+ */
56
+ declare function useInComposer(force?: boolean): boolean;
57
+ /** @deprecated Prefer `useInComposer`. Kept for internal AmplifyPageContent. */
58
+ declare function useComposerPreviewFlag(force?: boolean): boolean;
59
+
46
60
  declare function ComponentContextProvider({ children, slots, props, layoutNodeId, componentId, }: {
47
61
  children: ReactNode;
48
62
  slots?: Record<string, ReactNode>;
@@ -168,6 +182,24 @@ declare function Image<T = unknown>(props: {
168
182
  alt?: string;
169
183
  } & Omit<react__default.ImgHTMLAttributes<HTMLImageElement>, 'src' | 'alt' | 'name'>): react_jsx_runtime.JSX.Element | null;
170
184
 
185
+ /** Tells Slot whether the layout/provider fetch has settled. */
186
+ declare function ComposerLayoutStatusProvider({ ready, children, }: {
187
+ ready: boolean;
188
+ children: ReactNode;
189
+ }): react_jsx_runtime.JSX.Element;
190
+
191
+ /** Composer slot lifecycle. Loading ≠ empty. */
192
+ type SlotState = 'loading' | 'empty' | 'filled';
193
+ declare function resolveSlotState(opts: {
194
+ layoutReady: boolean;
195
+ hasContent: boolean;
196
+ }): SlotState;
197
+ /** Add-component affordance is only for a resolved, empty slot. */
198
+ declare function slotShowsAddComponent(state: SlotState): boolean;
199
+ declare function slotStateFromEl(el: {
200
+ getAttribute: (name: string) => string | null;
201
+ } | null | undefined): SlotState | null;
202
+
171
203
  declare function ComposerProvider({ children, }: {
172
204
  children: ReactNode;
173
205
  }): react_jsx_runtime.JSX.Element;
@@ -196,4 +228,4 @@ interface AmplifyUpProviderProps {
196
228
  declare function AmplifyUpProvider({ children, config, pageContext, }: AmplifyUpProviderProps): react_jsx_runtime.JSX.Element;
197
229
  declare function useAmplifyUp(): AmplifyUpContextType;
198
230
 
199
- export { AmplifyContentMeta, AmplifyPageContent, AmplifyUpProvider, ComponentContextProvider, ComposerProvider, ContentSource, Field, Field$1 as FieldEnvelope, Image, LayoutComponentProps, MaybeComposerProvider, PageConfig, RichText, Slot, useAmplifyUp };
231
+ export { AmplifyContentMeta, AmplifyPageContent, AmplifyUpProvider, ComponentContextProvider, ComposerLayoutStatusProvider, ComposerProvider, ContentSource, Field, Field$1 as FieldEnvelope, Image, LayoutComponentProps, MaybeComposerProvider, PageConfig, RichText, Slot, type SlotState, resolveSlotState, slotShowsAddComponent, slotStateFromEl, useAmplifyUp, useComposerPreviewFlag, useInComposer };
package/dist/react.d.ts CHANGED
@@ -43,6 +43,20 @@ interface AmplifyPageContentProps {
43
43
  */
44
44
  declare function AmplifyPageContent({ fallback, renderComponent, pageConfig: pageConfigProp, forceComposerPreview, previewLoadingComponent, previewEmptyComponent, loadingComponent, emptyComponent, errorComponent, }: AmplifyPageContentProps): react_jsx_runtime.JSX.Element | null;
45
45
 
46
+ /**
47
+ * True when the page is running inside AmplifyUp Composer.
48
+ *
49
+ * Safe to use for conditional render (e.g. expose a CSS-background image
50
+ * as a clickable `<Image>` only in Composer). First client render matches
51
+ * the server (`false`); detection runs after mount.
52
+ *
53
+ * @param force - When true (e.g. SSR already knows `?preview=true`), skip
54
+ * the post-mount flip and return true immediately.
55
+ */
56
+ declare function useInComposer(force?: boolean): boolean;
57
+ /** @deprecated Prefer `useInComposer`. Kept for internal AmplifyPageContent. */
58
+ declare function useComposerPreviewFlag(force?: boolean): boolean;
59
+
46
60
  declare function ComponentContextProvider({ children, slots, props, layoutNodeId, componentId, }: {
47
61
  children: ReactNode;
48
62
  slots?: Record<string, ReactNode>;
@@ -168,6 +182,24 @@ declare function Image<T = unknown>(props: {
168
182
  alt?: string;
169
183
  } & Omit<react__default.ImgHTMLAttributes<HTMLImageElement>, 'src' | 'alt' | 'name'>): react_jsx_runtime.JSX.Element | null;
170
184
 
185
+ /** Tells Slot whether the layout/provider fetch has settled. */
186
+ declare function ComposerLayoutStatusProvider({ ready, children, }: {
187
+ ready: boolean;
188
+ children: ReactNode;
189
+ }): react_jsx_runtime.JSX.Element;
190
+
191
+ /** Composer slot lifecycle. Loading ≠ empty. */
192
+ type SlotState = 'loading' | 'empty' | 'filled';
193
+ declare function resolveSlotState(opts: {
194
+ layoutReady: boolean;
195
+ hasContent: boolean;
196
+ }): SlotState;
197
+ /** Add-component affordance is only for a resolved, empty slot. */
198
+ declare function slotShowsAddComponent(state: SlotState): boolean;
199
+ declare function slotStateFromEl(el: {
200
+ getAttribute: (name: string) => string | null;
201
+ } | null | undefined): SlotState | null;
202
+
171
203
  declare function ComposerProvider({ children, }: {
172
204
  children: ReactNode;
173
205
  }): react_jsx_runtime.JSX.Element;
@@ -196,4 +228,4 @@ interface AmplifyUpProviderProps {
196
228
  declare function AmplifyUpProvider({ children, config, pageContext, }: AmplifyUpProviderProps): react_jsx_runtime.JSX.Element;
197
229
  declare function useAmplifyUp(): AmplifyUpContextType;
198
230
 
199
- export { AmplifyContentMeta, AmplifyPageContent, AmplifyUpProvider, ComponentContextProvider, ComposerProvider, ContentSource, Field, Field$1 as FieldEnvelope, Image, LayoutComponentProps, MaybeComposerProvider, PageConfig, RichText, Slot, useAmplifyUp };
231
+ export { AmplifyContentMeta, AmplifyPageContent, AmplifyUpProvider, ComponentContextProvider, ComposerLayoutStatusProvider, ComposerProvider, ContentSource, Field, Field$1 as FieldEnvelope, Image, LayoutComponentProps, MaybeComposerProvider, PageConfig, RichText, Slot, type SlotState, resolveSlotState, slotShowsAddComponent, slotStateFromEl, useAmplifyUp, useComposerPreviewFlag, useInComposer };
package/dist/react.js CHANGED
@@ -1,13 +1,13 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
- var React2 = require('react');
4
+ var React3 = require('react');
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
6
  var marked = require('marked');
7
7
 
8
8
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
9
 
10
- var React2__default = /*#__PURE__*/_interopDefault(React2);
10
+ var React3__default = /*#__PURE__*/_interopDefault(React3);
11
11
 
12
12
  /* @amplifyup/sdk - https://amplifyup.ai */
13
13
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
@@ -1044,7 +1044,7 @@ function dedupeLayoutProviderFetch(key, fetchFn) {
1044
1044
  function previewLayoutReady(opts) {
1045
1045
  if (opts.hasClientLayout) return true;
1046
1046
  if (opts.clientLoading) return false;
1047
- return opts.hasServerLayout;
1047
+ return true;
1048
1048
  }
1049
1049
 
1050
1050
  // src/edge/normalizeRoute.ts
@@ -1515,33 +1515,11 @@ var AmplifyUpSDK = class {
1515
1515
  }
1516
1516
  }
1517
1517
  /**
1518
- * Detect if we're running in visual editor mode
1519
- * Returns true if:
1520
- * 1. Preview mode flag is set by proxy
1521
- * 2. We're in an iframe AND parent is from orchestrator domain
1522
- * 3. OR visualEditor/preview query parameter is present
1518
+ * Detect if we're running in visual editor mode.
1519
+ * Single source of truth: isComposerPreview() (flag, query, Composer referrer).
1523
1520
  */
1524
1521
  detectVisualEditorMode() {
1525
- if (typeof window === "undefined") return false;
1526
- if (window.__AMPLIFYUP_PREVIEW_MODE__ === true) {
1527
- return true;
1528
- }
1529
- const urlParams = new URLSearchParams(window.location.search);
1530
- if (urlParams.get("visualEditor") === "true" || urlParams.get("preview") === "true") {
1531
- return true;
1532
- }
1533
- const inIframe = window.self !== window.top;
1534
- if (!inIframe) return false;
1535
- try {
1536
- if (document.referrer) {
1537
- const referrerUrl = new URL(document.referrer);
1538
- if (referrerUrl.hostname === "localhost" && referrerUrl.port === "5001" || referrerUrl.pathname.includes("/dashboard/composer") || referrerUrl.pathname.includes("/dashboard/routes/")) {
1539
- return true;
1540
- }
1541
- }
1542
- } catch (e) {
1543
- }
1544
- return false;
1522
+ return isComposerPreview();
1545
1523
  }
1546
1524
  /**
1547
1525
  * Check if we're in preview/composer mode (should disable tracking)
@@ -3890,13 +3868,16 @@ function getSDK(adapter) {
3890
3868
  var trackContentView = (contentId, contentType, properties) => getSDK().trackContentView(contentId, contentType, properties);
3891
3869
  var refreshEventTracking = () => getSDK().refreshEventTracking();
3892
3870
  getSDK();
3893
- function useComposerPreviewFlag(force = false) {
3894
- const [detected, setDetected] = React2.useState(false);
3895
- React2.useEffect(() => {
3871
+ function useInComposer(force = false) {
3872
+ const [detected, setDetected] = React3.useState(false);
3873
+ React3.useEffect(() => {
3896
3874
  if (!force && isComposerPreview()) setDetected(true);
3897
3875
  }, [force]);
3898
3876
  return force || detected;
3899
3877
  }
3878
+ function useComposerPreviewFlag(force = false) {
3879
+ return useInComposer(force);
3880
+ }
3900
3881
 
3901
3882
  // src/composer-store.ts
3902
3883
  var ComposerFieldStore = class {
@@ -3939,19 +3920,19 @@ var ComposerFieldStore = class {
3939
3920
  for (const fn of set) fn();
3940
3921
  }
3941
3922
  };
3942
- var ComposerStoreContext = React2.createContext(null);
3943
- var ComposerNodeContext = React2.createContext(void 0);
3923
+ var ComposerStoreContext = React3.createContext(null);
3924
+ var ComposerNodeContext = React3.createContext(void 0);
3944
3925
  function applyComposerPatch(store, name, value, ref, layoutNodeId) {
3945
3926
  store.set(composerStoreKey(name, ref, layoutNodeId), value);
3946
3927
  }
3947
3928
  function ComposerProvider({
3948
3929
  children
3949
3930
  }) {
3950
- const existing = React2.useContext(ComposerStoreContext);
3951
- const storeRef = React2.useRef(null);
3931
+ const existing = React3.useContext(ComposerStoreContext);
3932
+ const storeRef = React3.useRef(null);
3952
3933
  if (!storeRef.current) storeRef.current = new ComposerFieldStore();
3953
3934
  const store = existing || storeRef.current;
3954
- React2.useEffect(() => {
3935
+ React3.useEffect(() => {
3955
3936
  if (existing) return;
3956
3937
  const applyField = (fieldName, value, nodeId, ref) => {
3957
3938
  if (!fieldName || typeof fieldName !== "string") return;
@@ -4015,10 +3996,10 @@ function ComposerProvider({
4015
3996
  return /* @__PURE__ */ jsxRuntime.jsx(ComposerStoreContext.Provider, { value: store, children });
4016
3997
  }
4017
3998
  function useComposerFieldValue(name, fallback, ref) {
4018
- const store = React2.useContext(ComposerStoreContext);
4019
- const layoutNodeId = React2.useContext(ComposerNodeContext);
3999
+ const store = React3.useContext(ComposerStoreContext);
4000
+ const layoutNodeId = React3.useContext(ComposerNodeContext);
4020
4001
  const key = composerStoreKey(name, ref, layoutNodeId);
4021
- const subscribe = React2.useCallback(
4002
+ const subscribe = React3.useCallback(
4022
4003
  (onStoreChange) => {
4023
4004
  if (!store || !name) return () => {
4024
4005
  };
@@ -4026,11 +4007,11 @@ function useComposerFieldValue(name, fallback, ref) {
4026
4007
  },
4027
4008
  [store, name, key]
4028
4009
  );
4029
- const getSnapshot = React2.useCallback(() => {
4010
+ const getSnapshot = React3.useCallback(() => {
4030
4011
  if (!store || !name) return void 0;
4031
4012
  return store.get(key);
4032
4013
  }, [store, name, key]);
4033
- const overlay = React2.useSyncExternalStore(subscribe, getSnapshot, () => void 0);
4014
+ const overlay = React3.useSyncExternalStore(subscribe, getSnapshot, () => void 0);
4034
4015
  return overlay !== void 0 ? overlay : fallback;
4035
4016
  }
4036
4017
  function MaybeComposerProvider({
@@ -4038,7 +4019,7 @@ function MaybeComposerProvider({
4038
4019
  layoutNodeId,
4039
4020
  children
4040
4021
  }) {
4041
- const content = React2.useMemo(() => children, [children]);
4022
+ const content = React3.useMemo(() => children, [children]);
4042
4023
  if (!enabled) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: content });
4043
4024
  return /* @__PURE__ */ jsxRuntime.jsx(ComposerProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(ComposerNodeContext.Provider, { value: layoutNodeId, children }) });
4044
4025
  }
@@ -4058,7 +4039,7 @@ function nodeRenderProps(node) {
4058
4039
  fields: branded
4059
4040
  };
4060
4041
  }
4061
- var ComponentRenderBoundary = class extends React2.Component {
4042
+ var ComponentRenderBoundary = class extends React3.Component {
4062
4043
  constructor() {
4063
4044
  super(...arguments);
4064
4045
  this.state = { error: null };
@@ -4131,8 +4112,8 @@ function AmplifyRendererInner({
4131
4112
  const loading = serverPageConfig ? false : clientHook.loading;
4132
4113
  const error = serverPageConfig ? null : clientHook.error;
4133
4114
  const contentSource = clientHook.source;
4134
- const [variantCache, setVariantCache] = React2.useState({});
4135
- React2.useEffect(() => {
4115
+ const [variantCache, setVariantCache] = React3.useState({});
4116
+ React3.useEffect(() => {
4136
4117
  if (typeof window !== "undefined") {
4137
4118
  if (window.__AMPLIFYUP_PREVIEW_MODE__ === true) {
4138
4119
  return;
@@ -4158,7 +4139,7 @@ function AmplifyRendererInner({
4158
4139
  });
4159
4140
  }
4160
4141
  }, [pageConfig]);
4161
- React2.useEffect(() => {
4142
+ React3.useEffect(() => {
4162
4143
  if (!pageConfig?.eventTracking?.length) return;
4163
4144
  const sdk = getSDK();
4164
4145
  if (!sdk.isInitialized()) return;
@@ -4176,7 +4157,7 @@ function AmplifyRendererInner({
4176
4157
  window.clearTimeout(t2);
4177
4158
  };
4178
4159
  }, [pageConfig?.id, pageConfig?.eventTracking]);
4179
- React2.useEffect(() => {
4160
+ React3.useEffect(() => {
4180
4161
  if (!pageConfig) return;
4181
4162
  const t = window.setTimeout(() => {
4182
4163
  getSDK().setupComponentViewTracking();
@@ -4184,27 +4165,8 @@ function AmplifyRendererInner({
4184
4165
  }, 100);
4185
4166
  return () => window.clearTimeout(t);
4186
4167
  }, [variantCache, pageConfig?.id]);
4187
- React2.useEffect(() => {
4188
- const isVisualEditorMode = () => {
4189
- if (typeof window === "undefined") return false;
4190
- const urlParams = new URLSearchParams(window.location.search);
4191
- if (urlParams.get("visualEditor") === "true" || urlParams.get("preview") === "true") {
4192
- return true;
4193
- }
4194
- const inIframe = window.self !== window.top;
4195
- if (!inIframe) return false;
4196
- try {
4197
- if (document.referrer) {
4198
- const referrerUrl = new URL(document.referrer);
4199
- if (referrerUrl.hostname === "localhost" && referrerUrl.port === "5001") {
4200
- return true;
4201
- }
4202
- }
4203
- } catch (e) {
4204
- }
4205
- return false;
4206
- };
4207
- if (!isVisualEditorMode()) {
4168
+ React3.useEffect(() => {
4169
+ if (!isComposerPreview()) {
4208
4170
  return;
4209
4171
  }
4210
4172
  if (!pageConfig) {
@@ -4278,7 +4240,7 @@ function AmplifyRendererInner({
4278
4240
  );
4279
4241
  }
4280
4242
  }, [pageConfig]);
4281
- React2.useEffect(() => {
4243
+ React3.useEffect(() => {
4282
4244
  if (!pageConfig?.layoutTree || !pageConfig.layoutId) return;
4283
4245
  const roots = pageConfig.layoutTree;
4284
4246
  const fromEdge = contentSource === "edge" || roots.some((n) => n._contentSource === "edge");
@@ -4419,7 +4381,7 @@ function AmplifyRendererInner({
4419
4381
  "data-amplifyup-slot": "content",
4420
4382
  "data-parent-node-id": node.id,
4421
4383
  "data-parent-component-id": "AmplifyZone",
4422
- children: children.filter(Boolean).map((child) => /* @__PURE__ */ jsxRuntime.jsx(React2.Fragment, { children: renderNode(child) }, child.id))
4384
+ children: children.filter(Boolean).map((child) => /* @__PURE__ */ jsxRuntime.jsx(React3.Fragment, { children: renderNode(child) }, child.id))
4423
4385
  }
4424
4386
  )
4425
4387
  }
@@ -4452,7 +4414,7 @@ function AmplifyRendererInner({
4452
4414
  "data-zone-id": slot.zoneId || void 0,
4453
4415
  "data-parent-node-id": node.id,
4454
4416
  "data-parent-component-id": node.componentId,
4455
- children: safeChildren.filter(Boolean).map((child) => /* @__PURE__ */ jsxRuntime.jsx(React2.Fragment, { children: renderNode(child) }, child.id))
4417
+ children: safeChildren.filter(Boolean).map((child) => /* @__PURE__ */ jsxRuntime.jsx(React3.Fragment, { children: renderNode(child) }, child.id))
4456
4418
  },
4457
4419
  slot.slotId
4458
4420
  );
@@ -4498,12 +4460,13 @@ function AmplifyRendererInner({
4498
4460
  "data-slot-id": "main",
4499
4461
  "data-amplifyup-slot": "main",
4500
4462
  "data-slot-source": "page",
4463
+ "data-slot-state": layoutTree.length === 0 ? "empty" : "filled",
4501
4464
  "data-slot-empty": layoutTree.length === 0 ? "true" : void 0,
4502
- children: layoutTree.map((node) => /* @__PURE__ */ jsxRuntime.jsx(React2.Fragment, { children: renderNode(node) }, node.id))
4465
+ children: layoutTree.map((node) => /* @__PURE__ */ jsxRuntime.jsx(React3.Fragment, { children: renderNode(node) }, node.id))
4503
4466
  }
4504
- ) : layoutTree.map((node) => /* @__PURE__ */ jsxRuntime.jsx(React2.Fragment, { children: renderNode(node) }, node.id)) }) });
4467
+ ) : layoutTree.map((node) => /* @__PURE__ */ jsxRuntime.jsx(React3.Fragment, { children: renderNode(node) }, node.id)) }) });
4505
4468
  }
4506
- var AmplifyRenderer = React2.memo(AmplifyRendererInner);
4469
+ var AmplifyRenderer = React3.memo(AmplifyRendererInner);
4507
4470
  function AddComponentIcon({ size = 28 }) {
4508
4471
  return /* @__PURE__ */ jsxRuntime.jsxs(
4509
4472
  "svg",
@@ -4598,16 +4561,34 @@ function EmptySlotHint({
4598
4561
  }
4599
4562
  );
4600
4563
  }
4601
- function defaultPreviewCanvas() {
4564
+ var ComposerLayoutStatusContext = React3.createContext({
4565
+ ready: true
4566
+ });
4567
+ function ComposerLayoutStatusProvider({
4568
+ ready,
4569
+ children
4570
+ }) {
4571
+ return /* @__PURE__ */ jsxRuntime.jsx(ComposerLayoutStatusContext.Provider, { value: { ready }, children });
4572
+ }
4573
+ function useComposerLayoutStatus() {
4574
+ return React3.useContext(ComposerLayoutStatusContext);
4575
+ }
4576
+ function previewPageSlot(state) {
4602
4577
  return /* @__PURE__ */ jsxRuntime.jsx(
4603
4578
  "div",
4604
4579
  {
4605
4580
  "data-slot-id": "main",
4606
4581
  "data-amplifyup-slot": "main",
4607
4582
  "data-slot-source": "page",
4608
- "data-slot-empty": "true",
4609
- style: { minHeight: "50vh", width: "100%", display: "block", position: "relative" },
4610
- children: /* @__PURE__ */ jsxRuntime.jsx(EmptySlotHint, {})
4583
+ "data-slot-state": state,
4584
+ "data-slot-empty": state === "empty" ? "true" : void 0,
4585
+ style: {
4586
+ minHeight: state === "empty" ? "50vh" : void 0,
4587
+ width: "100%",
4588
+ display: "block",
4589
+ position: "relative"
4590
+ },
4591
+ children: state === "empty" ? /* @__PURE__ */ jsxRuntime.jsx(EmptySlotHint, {}) : null
4611
4592
  }
4612
4593
  );
4613
4594
  }
@@ -4654,25 +4635,26 @@ function AmplifyPageContent({
4654
4635
  }
4655
4636
  const loading = !hasAmplifyLayout(pageConfig) && client.loading;
4656
4637
  const error = hasAmplifyLayout(pageConfig) ? null : pageConfigProp ? null : client.error;
4657
- const previewCanvas = previewEmptyComponent ?? defaultPreviewCanvas();
4658
- const previewLoading = previewLoadingComponent ?? previewCanvas;
4638
+ const previewEmpty = previewEmptyComponent ?? previewPageSlot("empty");
4639
+ const previewLoading = previewLoadingComponent ?? previewPageSlot("loading");
4659
4640
  if (preview) {
4660
4641
  const ready = previewLayoutReady({
4661
4642
  clientLoading: client.loading,
4662
- hasClientLayout: !!clientLayout,
4663
- hasServerLayout: !!serverLayout
4664
- });
4665
- return /* @__PURE__ */ jsxRuntime.jsx(
4643
+ hasClientLayout: !!clientLayout});
4644
+ if (!ready) {
4645
+ return /* @__PURE__ */ jsxRuntime.jsx(ComposerLayoutStatusProvider, { ready: false, children: previewLoading });
4646
+ }
4647
+ return /* @__PURE__ */ jsxRuntime.jsx(ComposerLayoutStatusProvider, { ready: true, children: /* @__PURE__ */ jsxRuntime.jsx(
4666
4648
  AmplifyRenderer,
4667
4649
  {
4668
- pageConfig: ready ? pageConfig ?? void 0 : void 0,
4650
+ pageConfig: pageConfig ?? void 0,
4669
4651
  renderComponent,
4670
4652
  composerPreview: true,
4671
4653
  loadingComponent: loadingComponent ?? previewLoading,
4672
- emptyComponent: emptyComponent ?? previewCanvas,
4673
- errorComponent: errorComponent ?? (() => previewCanvas)
4654
+ emptyComponent: emptyComponent ?? previewEmpty,
4655
+ errorComponent: errorComponent ?? (() => previewEmpty)
4674
4656
  }
4675
- );
4657
+ ) });
4676
4658
  }
4677
4659
  if (loading) {
4678
4660
  return loadingComponent ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: loadingComponent }) : null;
@@ -4696,6 +4678,24 @@ function AmplifyPageContent({
4696
4678
  );
4697
4679
  }
4698
4680
 
4681
+ // src/slot-state.ts
4682
+ function resolveSlotState(opts) {
4683
+ if (!opts.layoutReady) return "loading";
4684
+ return opts.hasContent ? "filled" : "empty";
4685
+ }
4686
+ function slotShowsAddComponent(state) {
4687
+ return state === "empty";
4688
+ }
4689
+ function slotStateFromEl(el) {
4690
+ if (!el) return null;
4691
+ const explicit = el.getAttribute("data-slot-state");
4692
+ if (explicit === "loading" || explicit === "empty" || explicit === "filled") {
4693
+ return explicit;
4694
+ }
4695
+ if (el.getAttribute("data-slot-empty") === "true") return "empty";
4696
+ return null;
4697
+ }
4698
+
4699
4699
  // src/composer-edit-mode.ts
4700
4700
  function isComposerEditMode() {
4701
4701
  if (typeof window === "undefined") return false;
@@ -4710,7 +4710,7 @@ function subscribeComposerEdit(onStoreChange) {
4710
4710
  function getComposerEditModeServer() {
4711
4711
  return false;
4712
4712
  }
4713
- var ComponentContext = React2.createContext(null);
4713
+ var ComponentContext = React3.createContext(null);
4714
4714
  function ComponentContextProvider({
4715
4715
  children,
4716
4716
  slots,
@@ -4731,13 +4731,18 @@ function Slot({
4731
4731
  name,
4732
4732
  className
4733
4733
  }) {
4734
- const context = React2.useContext(ComponentContext);
4734
+ const context = React3.useContext(ComponentContext);
4735
4735
  if (!context) {
4736
4736
  console.warn(`[AmplifyUp SDK] Slot "${name}" used outside ComponentContextProvider`);
4737
4737
  return null;
4738
4738
  }
4739
4739
  const slotContent = context.slots?.[name];
4740
- const isEmpty = !slotContent;
4740
+ const { ready: layoutReady } = useComposerLayoutStatus();
4741
+ const slotState = resolveSlotState({
4742
+ layoutReady,
4743
+ hasContent: !!slotContent
4744
+ });
4745
+ const isEmpty = slotState === "empty";
4741
4746
  const isEditorMode = typeof window !== "undefined" && // Check for preview mode flag set by proxy
4742
4747
  (window.__AMPLIFYUP_PREVIEW_MODE__ === true || // Check URL query params
4743
4748
  new URLSearchParams(window.location.search).get("preview") === "true" || new URLSearchParams(window.location.search).get("visualEditor") === "true" || // Check if in iframe from orchestrator (check referrer hostname/port)
@@ -4753,6 +4758,7 @@ function Slot({
4753
4758
  `slot:${context.layoutNodeId || ""}:${name}`,
4754
4759
  `[Slot:${name}]`,
4755
4760
  {
4761
+ slotState,
4756
4762
  isEmpty,
4757
4763
  isEditorMode,
4758
4764
  availableSlotKeys: context.slots ? Object.keys(context.slots) : []
@@ -4765,6 +4771,7 @@ function Slot({
4765
4771
  "data-slot-name": name,
4766
4772
  "data-slot-id": name,
4767
4773
  "data-amplifyup-slot": name,
4774
+ "data-slot-state": slotState,
4768
4775
  "data-slot-empty": isEmpty ? "true" : void 0,
4769
4776
  "data-parent-node-id": context.layoutNodeId || void 0,
4770
4777
  "data-parent-component-id": context.componentId || void 0,
@@ -4774,7 +4781,7 @@ function Slot({
4774
4781
  // Only add position relative for overlay positioning in editor mode
4775
4782
  position: isEditorMode ? "relative" : void 0
4776
4783
  },
4777
- children: isEmpty ? isEditorMode ? /* @__PURE__ */ jsxRuntime.jsx(EmptySlotHint, { compact: true }) : /* @__PURE__ */ jsxRuntime.jsx(
4784
+ children: slotState === "loading" ? null : isEmpty ? isEditorMode ? /* @__PURE__ */ jsxRuntime.jsx(EmptySlotHint, { compact: true }) : /* @__PURE__ */ jsxRuntime.jsx(
4778
4785
  "div",
4779
4786
  {
4780
4787
  className: "amplifyup-slot-placeholder",
@@ -4846,7 +4853,7 @@ function canInlineEditRichText(name, value) {
4846
4853
  return true;
4847
4854
  }
4848
4855
  function useComposerEditMode() {
4849
- return React2.useSyncExternalStore(
4856
+ return React3.useSyncExternalStore(
4850
4857
  subscribeComposerEdit,
4851
4858
  isComposerEditMode,
4852
4859
  getComposerEditModeServer
@@ -4924,14 +4931,14 @@ function ComposerInlineField({
4924
4931
  fieldRef,
4925
4932
  rich = false
4926
4933
  }) {
4927
- const [focused, setFocused] = React2.useState(false);
4928
- const elRef = React2.useRef(null);
4934
+ const [focused, setFocused] = React3.useState(false);
4935
+ const elRef = React3.useRef(null);
4929
4936
  const storedEmpty = isComposerEmptyText(value);
4930
4937
  const text = storedEmpty ? "" : formatFieldValue(value);
4931
4938
  const hint = COMPOSER_EMPTY_FIELD_HINT;
4932
4939
  const idleDisplay = storedEmpty ? hint : text;
4933
4940
  const showHint = storedEmpty && !focused;
4934
- React2.useEffect(() => {
4941
+ React3.useEffect(() => {
4935
4942
  const el = elRef.current;
4936
4943
  if (!el) return;
4937
4944
  if (document.activeElement === el) return;
@@ -5049,8 +5056,8 @@ function ComposerInlineHtml({
5049
5056
  componentId,
5050
5057
  fieldRef
5051
5058
  }) {
5052
- const elRef = React2.useRef(null);
5053
- React2.useEffect(() => {
5059
+ const elRef = React3.useRef(null);
5060
+ React3.useEffect(() => {
5054
5061
  const el = elRef.current;
5055
5062
  if (!el) return;
5056
5063
  if (el.innerHTML !== html) el.innerHTML = html;
@@ -5068,7 +5075,7 @@ function ComposerInlineHtml({
5068
5075
  fieldRef
5069
5076
  });
5070
5077
  };
5071
- return React2__default.default.createElement(Tag, {
5078
+ return React3__default.default.createElement(Tag, {
5072
5079
  ref: elRef,
5073
5080
  className,
5074
5081
  "data-amplifyup-field": name,
@@ -5167,7 +5174,7 @@ function hasOwnProp(props, key) {
5167
5174
  }
5168
5175
  function Field(props) {
5169
5176
  const { field, value, name, className } = props;
5170
- const context = React2.useContext(ComponentContext);
5177
+ const context = React3.useContext(ComponentContext);
5171
5178
  const composerEdit = useComposerEditMode();
5172
5179
  const hasField = isFieldEnvelope(field);
5173
5180
  const hasValue = hasOwnProp(props, "value");
@@ -5221,7 +5228,7 @@ function RichText(props) {
5221
5228
  as: Tag = "div",
5222
5229
  children
5223
5230
  } = props;
5224
- const context = React2.useContext(ComponentContext);
5231
+ const context = React3.useContext(ComponentContext);
5225
5232
  const composerEdit = useComposerEditMode();
5226
5233
  const childrenValue = typeof children === "string" || typeof children === "number" ? String(children) : void 0;
5227
5234
  const hasField = isFieldEnvelope(field);
@@ -5344,7 +5351,7 @@ function Image(props) {
5344
5351
  height: heightProp,
5345
5352
  ...imgProps
5346
5353
  } = props;
5347
- const context = React2.useContext(ComponentContext);
5354
+ const context = React3.useContext(ComponentContext);
5348
5355
  assertNamedEnvelope("Image", field);
5349
5356
  const coerced = coerceImageField(field, value, name);
5350
5357
  const boundField = coerced.field;
@@ -5431,7 +5438,7 @@ if (typeof window !== "undefined") {
5431
5438
  } catch {
5432
5439
  }
5433
5440
  }
5434
- var AmplifyUpContext = React2.createContext(null);
5441
+ var AmplifyUpContext = React3.createContext(null);
5435
5442
  function normalizeRoutePath2(route) {
5436
5443
  if (!route) return "";
5437
5444
  const path = route.split("?")[0] || "/";
@@ -5443,12 +5450,12 @@ function AmplifyUpProvider({
5443
5450
  config,
5444
5451
  pageContext
5445
5452
  }) {
5446
- const [initialized, setInitialized] = React2.useState(false);
5447
- const [pageConfig, setPageConfig] = React2.useState(null);
5448
- const [loading, setLoading] = React2.useState(true);
5449
- const [error, setError] = React2.useState(null);
5450
- const [source, setSource] = React2.useState(null);
5451
- const [meta, setMeta] = React2.useState(null);
5453
+ const [initialized, setInitialized] = React3.useState(false);
5454
+ const [pageConfig, setPageConfig] = React3.useState(null);
5455
+ const [loading, setLoading] = React3.useState(true);
5456
+ const [error, setError] = React3.useState(null);
5457
+ const [source, setSource] = React3.useState(null);
5458
+ const [meta, setMeta] = React3.useState(null);
5452
5459
  const getActualRoute = () => {
5453
5460
  if (typeof window === "undefined") return "";
5454
5461
  const currentPath = window.location.pathname;
@@ -5465,15 +5472,15 @@ function AmplifyUpProvider({
5465
5472
  }
5466
5473
  return currentPath;
5467
5474
  };
5468
- const loadedRouteRef = React2.useRef(null);
5475
+ const loadedRouteRef = React3.useRef(null);
5469
5476
  const nextPathname = usePathname ? usePathname() : null;
5470
- const [pathname, setPathname] = React2.useState(() => {
5477
+ const [pathname, setPathname] = React3.useState(() => {
5471
5478
  if (typeof window !== "undefined") {
5472
5479
  return getActualRoute();
5473
5480
  }
5474
5481
  return "";
5475
5482
  });
5476
- React2.useEffect(() => {
5483
+ React3.useEffect(() => {
5477
5484
  if (typeof window !== "undefined") {
5478
5485
  const actualRoute = getActualRoute();
5479
5486
  if (window.location.pathname === "/api/pages/proxy" || window.location.pathname.startsWith("/api/pages/proxy")) {
@@ -5500,11 +5507,11 @@ function AmplifyUpProvider({
5500
5507
  }
5501
5508
  }, [nextPathname]);
5502
5509
  const pageContextKey = pageContext ? `${pageContext.resourceType}:${pageContext.key}` : "";
5503
- React2.useEffect(() => {
5510
+ React3.useEffect(() => {
5504
5511
  if (!initialized || !pageContext) return;
5505
5512
  getSDK().setPageContext(pageContext);
5506
5513
  }, [initialized, pageContextKey]);
5507
- React2.useEffect(() => {
5514
+ React3.useEffect(() => {
5508
5515
  let cancelled = false;
5509
5516
  const sdk = getSDK();
5510
5517
  const run = async () => {
@@ -5626,7 +5633,7 @@ function AmplifyUpProvider({
5626
5633
  config.clientPersonalization,
5627
5634
  pageContextKey
5628
5635
  ]);
5629
- React2.useEffect(() => {
5636
+ React3.useEffect(() => {
5630
5637
  const applyLayoutTree = (layoutTree) => {
5631
5638
  if (!Array.isArray(layoutTree)) return;
5632
5639
  setPageConfig((prev) => {
@@ -5668,7 +5675,7 @@ function AmplifyUpProvider({
5668
5675
  );
5669
5676
  }
5670
5677
  function useAmplifyUp() {
5671
- const context = React2.useContext(AmplifyUpContext);
5678
+ const context = React3.useContext(AmplifyUpContext);
5672
5679
  if (!context) {
5673
5680
  throw new Error("useAmplifyUp must be used within AmplifyUpProvider");
5674
5681
  }
@@ -5679,6 +5686,7 @@ exports.AmplifyPageContent = AmplifyPageContent;
5679
5686
  exports.AmplifyRenderer = AmplifyRenderer;
5680
5687
  exports.AmplifyUpProvider = AmplifyUpProvider;
5681
5688
  exports.ComponentContextProvider = ComponentContextProvider;
5689
+ exports.ComposerLayoutStatusProvider = ComposerLayoutStatusProvider;
5682
5690
  exports.ComposerProvider = ComposerProvider;
5683
5691
  exports.Field = Field;
5684
5692
  exports.Image = Image;
@@ -5699,9 +5707,14 @@ exports.isWorkingContentRequest = isWorkingContentRequest;
5699
5707
  exports.listOwnerFromSpec = listOwnerFromSpec;
5700
5708
  exports.nextPageSpec = nextPageSpec;
5701
5709
  exports.queryContent = queryContent;
5710
+ exports.resolveSlotState = resolveSlotState;
5702
5711
  exports.searchSpec = searchSpec;
5703
5712
  exports.selectVariants = selectVariants;
5713
+ exports.slotShowsAddComponent = slotShowsAddComponent;
5714
+ exports.slotStateFromEl = slotStateFromEl;
5704
5715
  exports.toFieldEnvelopes = toFieldEnvelopes;
5705
5716
  exports.useAmplifyUp = useAmplifyUp;
5717
+ exports.useComposerPreviewFlag = useComposerPreviewFlag;
5718
+ exports.useInComposer = useInComposer;
5706
5719
  //# sourceMappingURL=react.js.map
5707
5720
  //# sourceMappingURL=react.js.map