@amplifyup/sdk 0.1.27 → 0.1.29

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,7 +1,7 @@
1
1
  'use client';
2
2
  import { createContext, useState, useEffect, useContext, Fragment as Fragment$1, useRef, Component } from 'react';
3
- import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
4
3
  import { marked } from 'marked';
4
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
5
 
6
6
  /* @amplifyup/sdk - https://amplifyup.ai */
7
7
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
@@ -2741,125 +2741,588 @@ function getSDK(adapter) {
2741
2741
  var trackContentView = (contentId, contentType, properties) => getSDK().trackContentView(contentId, contentType, properties);
2742
2742
  var refreshEventTracking = () => getSDK().refreshEventTracking();
2743
2743
  getSDK();
2744
- var ComponentRenderBoundary = class extends Component {
2745
- constructor() {
2746
- super(...arguments);
2747
- this.state = { error: null };
2748
- }
2749
- static getDerivedStateFromError(error) {
2750
- return { error };
2751
- }
2752
- componentDidCatch(error) {
2753
- console.error(
2754
- `[AmplifyRenderer] "${this.props.componentId}" (${this.props.nodeId}) threw while rendering:`,
2755
- error
2744
+ var ComponentContext = createContext(null);
2745
+ function useLiveComposerProps(layoutNodeId, props) {
2746
+ const [live, setLive] = useState(props);
2747
+ useEffect(() => {
2748
+ setLive(props);
2749
+ }, [props]);
2750
+ useEffect(() => {
2751
+ const apply = (fieldName, value, nodeId) => {
2752
+ if (!fieldName || typeof fieldName !== "string") return;
2753
+ if (nodeId && layoutNodeId && String(nodeId) !== String(layoutNodeId)) {
2754
+ return;
2755
+ }
2756
+ setLive((prev) => ({ ...prev, [fieldName]: value }));
2757
+ };
2758
+ const onPatch = (event) => {
2759
+ const detail = event.detail || {};
2760
+ apply(detail.fieldName, detail.value, detail.layoutNodeId);
2761
+ };
2762
+ const onMessage = (event) => {
2763
+ if (event.data?.type !== "AMPLIFYUP_FIELD_PATCH") return;
2764
+ apply(event.data.fieldName, event.data.value, event.data.layoutNodeId);
2765
+ };
2766
+ window.addEventListener("amplifyup:field-patch", onPatch);
2767
+ window.addEventListener("message", onMessage);
2768
+ return () => {
2769
+ window.removeEventListener("amplifyup:field-patch", onPatch);
2770
+ window.removeEventListener("message", onMessage);
2771
+ };
2772
+ }, [layoutNodeId]);
2773
+ return live;
2774
+ }
2775
+ function useComponentProps() {
2776
+ const context = useContext(ComponentContext);
2777
+ if (!context) {
2778
+ console.warn(
2779
+ "[AmplifyUp SDK] useComponentProps used outside ComponentContextProvider"
2756
2780
  );
2781
+ return {};
2757
2782
  }
2758
- render() {
2759
- if (this.state.error) {
2760
- if (process.env.NODE_ENV !== "production") {
2761
- return /* @__PURE__ */ jsxs(
2783
+ return context.props || {};
2784
+ }
2785
+ function ComponentContextProvider({
2786
+ children,
2787
+ slots,
2788
+ props,
2789
+ layoutNodeId,
2790
+ componentId
2791
+ }) {
2792
+ const liveProps = useLiveComposerProps(layoutNodeId, props || {});
2793
+ return /* @__PURE__ */ jsx(
2794
+ ComponentContext.Provider,
2795
+ {
2796
+ value: { slots, props: liveProps, layoutNodeId, componentId },
2797
+ children
2798
+ }
2799
+ );
2800
+ }
2801
+ function Slot({
2802
+ name,
2803
+ className
2804
+ }) {
2805
+ const context = useContext(ComponentContext);
2806
+ console.log(`[Slot:${name}] Rendering slot`, {
2807
+ hasContext: !!context,
2808
+ availableSlotKeys: context?.slots ? Object.keys(context.slots) : [],
2809
+ slotContent: context?.slots?.[name] ? "EXISTS" : "MISSING",
2810
+ contextSlots: context?.slots
2811
+ });
2812
+ if (!context) {
2813
+ console.warn(`[AmplifyUp SDK] Slot "${name}" used outside ComponentContextProvider`);
2814
+ return null;
2815
+ }
2816
+ const slotContent = context.slots?.[name];
2817
+ const isEmpty = !slotContent;
2818
+ console.log(`[Slot:${name}] Slot state`, {
2819
+ isEmpty,
2820
+ hasSlotContent: !!slotContent,
2821
+ slotContentType: slotContent ? typeof slotContent : "null"
2822
+ });
2823
+ const isEditorMode = typeof window !== "undefined" && // Check for preview mode flag set by proxy
2824
+ (window.__AMPLIFYUP_PREVIEW_MODE__ === true || // Check URL query params
2825
+ 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)
2826
+ window.self !== window.top && document.referrer && (() => {
2827
+ try {
2828
+ const referrerUrl = new URL(document.referrer);
2829
+ return referrerUrl.hostname === "localhost" && referrerUrl.port === "5001" || referrerUrl.pathname.includes("/dashboard/composer") || referrerUrl.pathname.includes("/dashboard/routes/");
2830
+ } catch {
2831
+ return false;
2832
+ }
2833
+ })());
2834
+ console.log(`[Slot:${name}] Editor mode detection`, {
2835
+ isEditorMode,
2836
+ isWindowDefined: typeof window !== "undefined",
2837
+ previewModeFlag: typeof window !== "undefined" ? window.__AMPLIFYUP_PREVIEW_MODE__ : void 0,
2838
+ urlParams: typeof window !== "undefined" ? {
2839
+ preview: new URLSearchParams(window.location.search).get("preview"),
2840
+ visualEditor: new URLSearchParams(window.location.search).get("visualEditor")
2841
+ } : void 0,
2842
+ inIframe: typeof window !== "undefined" ? window.self !== window.top : false,
2843
+ referrer: typeof window !== "undefined" && document.referrer ? document.referrer : void 0
2844
+ });
2845
+ return /* @__PURE__ */ jsx(
2846
+ "div",
2847
+ {
2848
+ className,
2849
+ "data-slot-name": name,
2850
+ "data-slot-id": name,
2851
+ "data-amplifyup-slot": name,
2852
+ "data-slot-empty": isEmpty ? "true" : void 0,
2853
+ "data-parent-node-id": context.layoutNodeId || void 0,
2854
+ "data-parent-component-id": context.componentId || void 0,
2855
+ style: {
2856
+ // Only add minimum height when empty (for drop target visibility)
2857
+ minHeight: isEmpty ? "60px" : void 0,
2858
+ // Only add position relative for overlay positioning in editor mode
2859
+ position: isEditorMode ? "relative" : void 0
2860
+ },
2861
+ children: isEmpty ? /* @__PURE__ */ jsx(
2862
+ "div",
2863
+ {
2864
+ className: "amplifyup-slot-placeholder",
2865
+ style: {
2866
+ minHeight: "60px",
2867
+ color: "#9ca3af",
2868
+ fontSize: "14px",
2869
+ pointerEvents: "none"
2870
+ },
2871
+ children: isEditorMode ? `Drop components here` : `Empty slot: ${name}`
2872
+ }
2873
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
2874
+ isEditorMode && /* @__PURE__ */ jsxs(
2762
2875
  "div",
2763
2876
  {
2764
- "data-amplifyup-render-error": "",
2765
- "data-component-id": this.props.componentId,
2766
- "data-node-id": this.props.nodeId,
2877
+ className: "amplifyup-slot-placeholder",
2767
2878
  style: {
2768
- margin: "1rem 0",
2769
- padding: "0.75rem 1rem",
2770
- border: "1px solid #fca5a5",
2771
- borderRadius: "0.5rem",
2772
- background: "#fef2f2",
2773
- color: "#991b1b",
2774
- fontSize: "0.875rem"
2879
+ position: "absolute",
2880
+ top: "4px",
2881
+ left: "4px",
2882
+ fontSize: "10px",
2883
+ color: "#9ca3af",
2884
+ pointerEvents: "none",
2885
+ zIndex: 1,
2886
+ minHeight: "auto"
2775
2887
  },
2776
2888
  children: [
2777
- 'Component "',
2778
- this.props.componentId,
2779
- '" failed to render:',
2780
- " ",
2781
- this.state.error.message
2889
+ "Slot: ",
2890
+ name
2782
2891
  ]
2783
2892
  }
2784
- );
2785
- }
2786
- return null;
2893
+ ),
2894
+ slotContent
2895
+ ] })
2787
2896
  }
2788
- return this.props.children;
2897
+ );
2898
+ }
2899
+ function isComposerEditMode() {
2900
+ if (typeof window === "undefined") return false;
2901
+ return isComposerPreview() && window.__AMPLIFYUP_EVENT_SELECTION__ !== true;
2902
+ }
2903
+ function isLikelyNonTextFieldName(name) {
2904
+ const n = name.toLowerCase();
2905
+ return n.includes("href") || n.includes("url") || n.includes("src") || n.includes("image") || n.includes("icon") || n.includes("overlay") || n.includes("color");
2906
+ }
2907
+ function canInlineEdit(name, value) {
2908
+ if (isLikelyNonTextFieldName(name)) return false;
2909
+ if (value !== void 0 && value !== null && typeof value === "object") {
2910
+ return false;
2789
2911
  }
2790
- };
2791
- function AmplifyRenderer({
2792
- renderComponent,
2793
- pageConfig: serverPageConfig,
2794
- loadingComponent,
2795
- errorComponent,
2796
- emptyComponent,
2797
- composerPreview
2798
- }) {
2799
- const clientHook = useAmplifyUp();
2800
- const pageConfig = serverPageConfig || clientHook.pageConfig || null;
2801
- const loading = serverPageConfig ? false : clientHook.loading;
2802
- const error = serverPageConfig ? null : clientHook.error;
2803
- const contentSource = clientHook.source;
2804
- const [variantCache, setVariantCache] = useState({});
2912
+ if (typeof value === "boolean") return false;
2913
+ return true;
2914
+ }
2915
+ function useComposerEditMode() {
2916
+ const [enabled, setEnabled] = useState(false);
2805
2917
  useEffect(() => {
2806
- if (typeof window !== "undefined") {
2807
- if (window.__AMPLIFYUP_PREVIEW_MODE__ === true) {
2808
- return;
2809
- }
2810
- if (window.location.pathname.includes("/api/pages/proxy")) {
2811
- return;
2812
- }
2813
- if (window.self !== window.top) {
2814
- return;
2815
- }
2816
- const urlParams = new URLSearchParams(window.location.search);
2817
- if (urlParams.get("preview") === "true" || urlParams.get("visualEditor") === "true") {
2818
- return;
2819
- }
2820
- if (window.location.href.includes("preview=true") || window.location.href.includes("visualEditor=true")) {
2918
+ const sync = () => setEnabled(isComposerEditMode());
2919
+ sync();
2920
+ window.addEventListener("amplifyup:composer-edit", sync);
2921
+ return () => window.removeEventListener("amplifyup:composer-edit", sync);
2922
+ }, []);
2923
+ return enabled;
2924
+ }
2925
+ function useFieldOverlay(layoutNodeId, name, source) {
2926
+ const [overlay, setOverlay] = useState(void 0);
2927
+ useEffect(() => {
2928
+ const onPatch = (event) => {
2929
+ const detail = event.detail || {};
2930
+ if (detail.fieldName !== name) return;
2931
+ if (detail.layoutNodeId && layoutNodeId && String(detail.layoutNodeId) !== String(layoutNodeId)) {
2821
2932
  return;
2822
2933
  }
2823
- }
2824
- if (pageConfig && pageConfig.id !== "default") {
2825
- trackContentView(pageConfig.id, "page", {
2826
- route: pageConfig.route,
2827
- title: pageConfig.title
2828
- });
2829
- }
2830
- }, [pageConfig]);
2831
- useEffect(() => {
2832
- if (!pageConfig?.eventTracking?.length) return;
2833
- const sdk = getSDK();
2834
- if (!sdk.isInitialized()) return;
2835
- sdk.setupEventTracking(pageConfig.eventTracking);
2836
- const t1 = window.setTimeout(() => {
2837
- sdk.setupComponentViewTracking();
2838
- refreshEventTracking();
2839
- }, 200);
2840
- const t2 = window.setTimeout(() => {
2841
- sdk.setupComponentViewTracking();
2842
- refreshEventTracking();
2843
- }, 1e3);
2844
- return () => {
2845
- window.clearTimeout(t1);
2846
- window.clearTimeout(t2);
2934
+ setOverlay(detail.value);
2847
2935
  };
2848
- }, [pageConfig?.id]);
2849
- useEffect(() => {
2850
- if (!pageConfig) return;
2851
- const t = window.setTimeout(() => {
2852
- getSDK().setupComponentViewTracking();
2853
- refreshEventTracking();
2854
- }, 100);
2855
- return () => window.clearTimeout(t);
2856
- }, [variantCache, pageConfig?.id]);
2857
- useEffect(() => {
2858
- const isVisualEditorMode = () => {
2859
- if (typeof window === "undefined") return false;
2860
- const urlParams = new URLSearchParams(window.location.search);
2861
- if (urlParams.get("visualEditor") === "true" || urlParams.get("preview") === "true") {
2862
- return true;
2936
+ window.addEventListener("amplifyup:field-patch", onPatch);
2937
+ return () => window.removeEventListener("amplifyup:field-patch", onPatch);
2938
+ }, [layoutNodeId, name]);
2939
+ return overlay !== void 0 ? overlay : source;
2940
+ }
2941
+ function commitComposerField(layoutNodeId, componentId, name, value) {
2942
+ if (typeof window === "undefined" || window.parent === window) return;
2943
+ window.parent.postMessage(
2944
+ {
2945
+ type: "AMPLIFYUP_FIELD_COMMIT",
2946
+ layoutNodeId,
2947
+ componentId,
2948
+ fieldName: name,
2949
+ value
2950
+ },
2951
+ "*"
2952
+ );
2953
+ }
2954
+ function ComposerInlineField({
2955
+ name,
2956
+ value,
2957
+ fallback,
2958
+ className,
2959
+ render,
2960
+ layoutNodeId,
2961
+ componentId
2962
+ }) {
2963
+ const [editing, setEditing] = useState(false);
2964
+ const elRef = useRef(null);
2965
+ const text = formatFieldValue(value);
2966
+ const fallbackText = typeof fallback === "string" || typeof fallback === "number" ? String(fallback) : "";
2967
+ const display = text || fallbackText;
2968
+ const showRendered = !!render && !editing;
2969
+ useEffect(() => {
2970
+ const el = elRef.current;
2971
+ if (!el || showRendered) return;
2972
+ if (document.activeElement === el) return;
2973
+ const next = display || "";
2974
+ if (el.textContent !== next) el.textContent = next;
2975
+ }, [display, showRendered]);
2976
+ useEffect(() => {
2977
+ if (!editing || !elRef.current) return;
2978
+ const el = elRef.current;
2979
+ el.textContent = display || "";
2980
+ el.focus();
2981
+ const range = document.createRange();
2982
+ range.selectNodeContents(el);
2983
+ const sel = window.getSelection();
2984
+ sel?.removeAllRanges();
2985
+ sel?.addRange(range);
2986
+ }, [editing]);
2987
+ const finishEdit = () => {
2988
+ const raw = (elRef.current?.innerText ?? "").replace(/\u00a0/g, " ").replace(/\n+$/g, "");
2989
+ const next = raw.trim() === "" ? "" : raw;
2990
+ setEditing(false);
2991
+ if (next === text) return;
2992
+ if (!text && next === fallbackText) return;
2993
+ commitComposerField(layoutNodeId, componentId, name, next);
2994
+ };
2995
+ return /* @__PURE__ */ jsx(
2996
+ "span",
2997
+ {
2998
+ ref: elRef,
2999
+ className,
3000
+ "data-amplifyup-field": name,
3001
+ "data-amplifyup-node-id": layoutNodeId || void 0,
3002
+ contentEditable: !showRendered,
3003
+ suppressContentEditableWarning: true,
3004
+ role: "textbox",
3005
+ tabIndex: 0,
3006
+ onMouseDown: (event) => {
3007
+ event.stopPropagation();
3008
+ },
3009
+ onClick: (event) => {
3010
+ const link = event.target?.closest?.("a");
3011
+ if (link) event.preventDefault();
3012
+ if (render && isComposerEditMode()) {
3013
+ setEditing(true);
3014
+ }
3015
+ },
3016
+ onFocus: () => {
3017
+ if (!isComposerEditMode()) return;
3018
+ if (render) setEditing(true);
3019
+ },
3020
+ onBlur: finishEdit,
3021
+ onKeyDown: (event) => {
3022
+ event.stopPropagation();
3023
+ if (event.key === "Enter" && !event.shiftKey) {
3024
+ event.preventDefault();
3025
+ event.currentTarget.blur();
3026
+ }
3027
+ if (event.key === "Escape") {
3028
+ event.preventDefault();
3029
+ if (elRef.current) elRef.current.textContent = display || "";
3030
+ setEditing(false);
3031
+ event.currentTarget.blur();
3032
+ }
3033
+ },
3034
+ style: {
3035
+ cursor: "text",
3036
+ outline: "1px dashed color-mix(in srgb, currentColor 40%, transparent)",
3037
+ outlineOffset: "2px",
3038
+ minWidth: "1ch",
3039
+ display: render ? void 0 : "inline"
3040
+ },
3041
+ children: showRendered ? value != null && value !== "" ? render(value) : fallback ?? display : null
3042
+ }
3043
+ );
3044
+ }
3045
+ function formatFieldValue(value) {
3046
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
3047
+ return String(value);
3048
+ }
3049
+ if (Array.isArray(value)) {
3050
+ const parts = value.map((item) => {
3051
+ if (typeof item === "string") return item;
3052
+ if (item && typeof item === "object" && "children" in item && Array.isArray(item.children)) {
3053
+ return item.children.map((c) => typeof c?.text === "string" ? c.text : "").join("");
3054
+ }
3055
+ return "";
3056
+ }).filter(Boolean);
3057
+ if (parts.length > 0) return parts.join(" ");
3058
+ }
3059
+ if (value && typeof value === "object") {
3060
+ return "";
3061
+ }
3062
+ return "";
3063
+ }
3064
+ function isLinkListItem(value) {
3065
+ return !!value && typeof value === "object" && !Array.isArray(value);
3066
+ }
3067
+ function renderLinkList(items, className) {
3068
+ const links = items.filter(isLinkListItem).filter((item) => {
3069
+ const label = typeof item.label === "string" ? item.label.trim() : "";
3070
+ const href = typeof item.href === "string" ? item.href.trim() : "";
3071
+ return !!(label || href);
3072
+ });
3073
+ if (links.length === 0) return null;
3074
+ return /* @__PURE__ */ jsx("span", { className, style: { display: "contents" }, children: links.map((item, index) => {
3075
+ const label = typeof item.label === "string" && item.label.trim() ? item.label : typeof item.href === "string" ? item.href : "Link";
3076
+ const href = typeof item.href === "string" && item.href.trim() ? item.href : "#";
3077
+ const style = typeof item.style === "string" ? item.style.trim() : "";
3078
+ return /* @__PURE__ */ jsx(
3079
+ "a",
3080
+ {
3081
+ href,
3082
+ target: item.openInNewTab ? "_blank" : void 0,
3083
+ rel: item.openInNewTab ? "noreferrer" : void 0,
3084
+ "data-amplifyup-action-style": style || void 0,
3085
+ children: label
3086
+ },
3087
+ typeof item._key === "string" && item._key ? item._key : `${href}-${index}`
3088
+ );
3089
+ }) });
3090
+ }
3091
+ function Field({
3092
+ name,
3093
+ fallback,
3094
+ className,
3095
+ render
3096
+ }) {
3097
+ const context = useContext(ComponentContext);
3098
+ const composerEdit = useComposerEditMode();
3099
+ const fieldValue = useFieldOverlay(
3100
+ context?.layoutNodeId,
3101
+ name,
3102
+ context?.props?.[name]
3103
+ );
3104
+ if (!context) {
3105
+ console.warn(`[AmplifyUp SDK] Field "${name}" used outside ComponentContextProvider`);
3106
+ return fallback ? /* @__PURE__ */ jsx(Fragment, { children: fallback }) : null;
3107
+ }
3108
+ if (render) {
3109
+ return /* @__PURE__ */ jsx("span", { className, style: { display: "contents" }, children: render(fieldValue) });
3110
+ }
3111
+ if (composerEdit && canInlineEdit(name, fieldValue)) {
3112
+ return /* @__PURE__ */ jsx(
3113
+ ComposerInlineField,
3114
+ {
3115
+ name,
3116
+ value: fieldValue,
3117
+ fallback,
3118
+ className,
3119
+ layoutNodeId: context.layoutNodeId,
3120
+ componentId: context.componentId
3121
+ }
3122
+ );
3123
+ }
3124
+ if (fieldValue === void 0 || fieldValue === null) {
3125
+ return fallback ? /* @__PURE__ */ jsx("span", { className, children: fallback }) : null;
3126
+ }
3127
+ if (Array.isArray(fieldValue)) {
3128
+ const list = renderLinkList(fieldValue, className);
3129
+ if (list) return list;
3130
+ }
3131
+ const text = formatFieldValue(fieldValue);
3132
+ if (!text) {
3133
+ return fallback ? /* @__PURE__ */ jsx("span", { className, children: fallback }) : null;
3134
+ }
3135
+ return /* @__PURE__ */ jsx("span", { className, children: text });
3136
+ }
3137
+ function markdownToHtml(markdown) {
3138
+ try {
3139
+ const result = marked.parse(markdown, { async: false });
3140
+ return typeof result === "string" ? result : "";
3141
+ } catch {
3142
+ return markdown;
3143
+ }
3144
+ }
3145
+ function RichText({
3146
+ name,
3147
+ fallback,
3148
+ className,
3149
+ as: Tag = "div"
3150
+ }) {
3151
+ const context = useContext(ComponentContext);
3152
+ const composerEdit = useComposerEditMode();
3153
+ const fieldValue = useFieldOverlay(
3154
+ context?.layoutNodeId,
3155
+ name,
3156
+ context?.props?.[name]
3157
+ );
3158
+ if (!context) {
3159
+ console.warn(`[AmplifyUp SDK] RichText "${name}" used outside ComponentContextProvider`);
3160
+ return fallback ? /* @__PURE__ */ jsx(Fragment, { children: fallback }) : null;
3161
+ }
3162
+ if (composerEdit && canInlineEdit(name, fieldValue)) {
3163
+ return /* @__PURE__ */ jsx(
3164
+ ComposerInlineField,
3165
+ {
3166
+ name,
3167
+ value: fieldValue,
3168
+ fallback,
3169
+ className,
3170
+ layoutNodeId: context.layoutNodeId,
3171
+ componentId: context.componentId
3172
+ }
3173
+ );
3174
+ }
3175
+ if (fieldValue === void 0 || fieldValue === null || fieldValue === "") {
3176
+ return fallback ? /* @__PURE__ */ jsx(Tag, { className, children: fallback }) : null;
3177
+ }
3178
+ let html = "";
3179
+ if (typeof fieldValue === "string") {
3180
+ const trimmed = fieldValue.trim();
3181
+ if (trimmed.startsWith("<") && trimmed.includes(">")) {
3182
+ html = fieldValue;
3183
+ } else {
3184
+ html = markdownToHtml(fieldValue);
3185
+ }
3186
+ } else {
3187
+ const text = formatFieldValue(fieldValue);
3188
+ html = text ? markdownToHtml(text) : "";
3189
+ }
3190
+ if (!html) {
3191
+ return fallback ? /* @__PURE__ */ jsx(Tag, { className, children: fallback }) : null;
3192
+ }
3193
+ return /* @__PURE__ */ jsx(Tag, { className, dangerouslySetInnerHTML: { __html: html } });
3194
+ }
3195
+ var ComponentRenderBoundary = class extends Component {
3196
+ constructor() {
3197
+ super(...arguments);
3198
+ this.state = { error: null };
3199
+ }
3200
+ static getDerivedStateFromError(error) {
3201
+ return { error };
3202
+ }
3203
+ componentDidCatch(error) {
3204
+ console.error(
3205
+ `[AmplifyRenderer] "${this.props.componentId}" (${this.props.nodeId}) threw while rendering:`,
3206
+ error
3207
+ );
3208
+ }
3209
+ render() {
3210
+ if (this.state.error) {
3211
+ if (process.env.NODE_ENV !== "production") {
3212
+ return /* @__PURE__ */ jsxs(
3213
+ "div",
3214
+ {
3215
+ "data-amplifyup-render-error": "",
3216
+ "data-component-id": this.props.componentId,
3217
+ "data-node-id": this.props.nodeId,
3218
+ style: {
3219
+ margin: "1rem 0",
3220
+ padding: "0.75rem 1rem",
3221
+ border: "1px solid #fca5a5",
3222
+ borderRadius: "0.5rem",
3223
+ background: "#fef2f2",
3224
+ color: "#991b1b",
3225
+ fontSize: "0.875rem"
3226
+ },
3227
+ children: [
3228
+ 'Component "',
3229
+ this.props.componentId,
3230
+ '" failed to render:',
3231
+ " ",
3232
+ this.state.error.message
3233
+ ]
3234
+ }
3235
+ );
3236
+ }
3237
+ return null;
3238
+ }
3239
+ return this.props.children;
3240
+ }
3241
+ };
3242
+ function LiveNodeRender({
3243
+ nodeId,
3244
+ componentId,
3245
+ props,
3246
+ slots,
3247
+ renderComponent
3248
+ }) {
3249
+ const liveProps = useLiveComposerProps(nodeId, props);
3250
+ return /* @__PURE__ */ jsx(Fragment, { children: renderComponent(componentId, liveProps, slots, {
3251
+ layoutNodeId: nodeId
3252
+ }) });
3253
+ }
3254
+ function AmplifyRenderer({
3255
+ renderComponent,
3256
+ pageConfig: serverPageConfig,
3257
+ loadingComponent,
3258
+ errorComponent,
3259
+ emptyComponent,
3260
+ composerPreview
3261
+ }) {
3262
+ const clientHook = useAmplifyUp();
3263
+ const pageConfig = serverPageConfig || clientHook.pageConfig || null;
3264
+ const loading = serverPageConfig ? false : clientHook.loading;
3265
+ const error = serverPageConfig ? null : clientHook.error;
3266
+ const contentSource = clientHook.source;
3267
+ const [variantCache, setVariantCache] = useState({});
3268
+ useEffect(() => {
3269
+ if (typeof window !== "undefined") {
3270
+ if (window.__AMPLIFYUP_PREVIEW_MODE__ === true) {
3271
+ return;
3272
+ }
3273
+ if (window.location.pathname.includes("/api/pages/proxy")) {
3274
+ return;
3275
+ }
3276
+ if (window.self !== window.top) {
3277
+ return;
3278
+ }
3279
+ const urlParams = new URLSearchParams(window.location.search);
3280
+ if (urlParams.get("preview") === "true" || urlParams.get("visualEditor") === "true") {
3281
+ return;
3282
+ }
3283
+ if (window.location.href.includes("preview=true") || window.location.href.includes("visualEditor=true")) {
3284
+ return;
3285
+ }
3286
+ }
3287
+ if (pageConfig && pageConfig.id !== "default") {
3288
+ trackContentView(pageConfig.id, "page", {
3289
+ route: pageConfig.route,
3290
+ title: pageConfig.title
3291
+ });
3292
+ }
3293
+ }, [pageConfig]);
3294
+ useEffect(() => {
3295
+ if (!pageConfig?.eventTracking?.length) return;
3296
+ const sdk = getSDK();
3297
+ if (!sdk.isInitialized()) return;
3298
+ sdk.setupEventTracking(pageConfig.eventTracking);
3299
+ const t1 = window.setTimeout(() => {
3300
+ sdk.setupComponentViewTracking();
3301
+ refreshEventTracking();
3302
+ }, 200);
3303
+ const t2 = window.setTimeout(() => {
3304
+ sdk.setupComponentViewTracking();
3305
+ refreshEventTracking();
3306
+ }, 1e3);
3307
+ return () => {
3308
+ window.clearTimeout(t1);
3309
+ window.clearTimeout(t2);
3310
+ };
3311
+ }, [pageConfig?.id]);
3312
+ useEffect(() => {
3313
+ if (!pageConfig) return;
3314
+ const t = window.setTimeout(() => {
3315
+ getSDK().setupComponentViewTracking();
3316
+ refreshEventTracking();
3317
+ }, 100);
3318
+ return () => window.clearTimeout(t);
3319
+ }, [variantCache, pageConfig?.id]);
3320
+ useEffect(() => {
3321
+ const isVisualEditorMode = () => {
3322
+ if (typeof window === "undefined") return false;
3323
+ const urlParams = new URLSearchParams(window.location.search);
3324
+ if (urlParams.get("visualEditor") === "true" || urlParams.get("preview") === "true") {
3325
+ return true;
2863
3326
  }
2864
3327
  const inIframe = window.self !== window.top;
2865
3328
  if (!inIframe) return false;
@@ -3055,619 +3518,233 @@ function AmplifyRenderer({
3055
3518
  /* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold text-red-900 mb-2", children: "Error Loading Page" }),
3056
3519
  /* @__PURE__ */ jsx("p", { className: "text-red-700", children: error })
3057
3520
  ] }) }) }) });
3058
- }
3059
- if (!pageConfig) {
3060
- return null;
3061
- }
3062
- pageConfig.layout?.header !== false;
3063
- pageConfig.layout?.footer !== false;
3064
- const renderNode = (node) => {
3065
- const zoneIdFromProps = node.componentId === "AmplifyZone" ? String(node.props?.zoneId || "") : "";
3066
- if (node.componentId === "AmplifyZone") {
3067
- const contentSlot = node.slots?.find((s) => s.slotId === "content") || node.slots?.[0];
3068
- const children = Array.isArray(contentSlot?.children) ? contentSlot.children : [];
3069
- return /* @__PURE__ */ jsx(
3070
- "div",
3071
- {
3072
- "data-node-id": node.id,
3073
- "data-amplifyup-node": "",
3074
- "data-amplifyup-component": "AmplifyZone",
3075
- "data-amplifyup-zone": zoneIdFromProps || void 0,
3076
- "data-zone-id": zoneIdFromProps || void 0,
3077
- children: /* @__PURE__ */ jsx(
3078
- "div",
3079
- {
3080
- "data-slot-id": "content",
3081
- "data-amplifyup-slot": "content",
3082
- "data-parent-node-id": node.id,
3083
- "data-parent-component-id": "AmplifyZone",
3084
- children: children.filter(Boolean).map((child) => /* @__PURE__ */ jsx(Fragment$1, { children: renderNode(child) }, child.id))
3085
- }
3086
- )
3087
- }
3088
- );
3089
- }
3090
- let slotChildren = {};
3091
- console.log(`[AmplifyRenderer] Rendering node ${node.id} (${node.componentId})`, {
3092
- hasSlots: !!(node.slots && node.slots.length > 0),
3093
- slotCount: node.slots?.length || 0,
3094
- slots: node.slots?.map((s) => ({ slotId: s.slotId, zoneId: s.zoneId, childrenCount: s.children?.length || 0 }))
3095
- });
3096
- if (node.slots && node.slots.length > 0) {
3097
- for (const slot of node.slots) {
3098
- const slotKey = `${node.id}-${slot.slotId}`;
3099
- let childrenToRender = [];
3100
- console.log(`[AmplifyRenderer] Processing slot ${slot.slotId} for node ${node.id}`, {
3101
- slotKey,
3102
- hasZoneId: !!slot.zoneId,
3103
- hasVariants: !!slot.variants,
3104
- hasVariantCache: !!variantCache[slotKey],
3105
- directChildrenCount: slot.children?.length || 0
3106
- });
3107
- if (slot.zoneId && slot.variants && variantCache[slotKey]) {
3108
- childrenToRender = variantCache[slotKey].children;
3109
- console.log(`[AmplifyRenderer] Using cached variant for slot ${slot.slotId}`, {
3110
- variantId: variantCache[slotKey].variantId,
3111
- childrenCount: childrenToRender.length
3112
- });
3113
- } else if (slot.zoneId && slot.variants) {
3114
- const defaultVariant = slot.variants.find((v) => v.isDefault);
3115
- childrenToRender = defaultVariant?.children || [];
3116
- console.log(`[AmplifyRenderer] Using default variant for slot ${slot.slotId}`, {
3117
- childrenCount: childrenToRender.length
3118
- });
3119
- } else {
3120
- childrenToRender = Array.isArray(slot.children) ? slot.children : [];
3121
- console.log(`[AmplifyRenderer] Using direct children for slot ${slot.slotId}`, {
3122
- childrenCount: childrenToRender.length
3123
- });
3124
- }
3125
- const safeChildren = Array.isArray(childrenToRender) ? childrenToRender : [];
3126
- slotChildren[slot.slotId] = /* @__PURE__ */ jsx(
3127
- "div",
3128
- {
3129
- "data-slot-id": slot.slotId,
3130
- "data-amplifyup-slot": slot.slotId,
3131
- "data-zone-id": slot.zoneId || void 0,
3132
- "data-parent-node-id": node.id,
3133
- "data-parent-component-id": node.componentId,
3134
- children: safeChildren.filter(Boolean).map((child) => /* @__PURE__ */ jsx(Fragment$1, { children: renderNode(child) }, child.id))
3135
- },
3136
- slot.slotId
3137
- );
3138
- console.log(`[AmplifyRenderer] Created slot content for ${slot.slotId}`, {
3139
- slotId: slot.slotId,
3140
- renderedChildrenCount: childrenToRender.length
3141
- });
3142
- }
3143
- }
3144
- const slotsToPass = Object.keys(slotChildren).length > 0 ? slotChildren : void 0;
3145
- console.log(`[AmplifyRenderer] Calling renderComponent for ${node.componentId}`, {
3146
- hasSlots: !!slotsToPass,
3147
- slotKeys: slotsToPass ? Object.keys(slotsToPass) : [],
3148
- propKeys: Object.keys(node.props || {}),
3149
- props: node.props || {}
3150
- });
3151
- return /* @__PURE__ */ jsx("div", { "data-node-id": node.id, "data-amplifyup-node": "", children: /* @__PURE__ */ jsx(
3152
- ComponentRenderBoundary,
3153
- {
3154
- componentId: node.componentId,
3155
- nodeId: node.id,
3156
- children: renderComponent(node.componentId, node.props || {}, slotsToPass, {
3157
- layoutNodeId: node.id
3158
- })
3159
- }
3160
- ) });
3161
- };
3162
- const rawTree = pageConfig.layoutTree;
3163
- const layoutTree = Array.isArray(rawTree) ? rawTree : rawTree && typeof rawTree === "object" && rawTree.componentId ? [rawTree] : [];
3164
- if (layoutTree.length === 0) {
3165
- 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." }) }) });
3166
- }
3167
- return /* @__PURE__ */ jsx("main", { children: composerPreview || isComposerPreview() ? /* @__PURE__ */ jsx(
3168
- "div",
3169
- {
3170
- "data-slot-id": "main",
3171
- "data-amplifyup-slot": "main",
3172
- "data-slot-source": "page",
3173
- "data-slot-empty": layoutTree.length === 0 ? "true" : void 0,
3174
- children: layoutTree.map((node) => /* @__PURE__ */ jsx("div", { children: renderNode(node) }, node.id))
3175
- }
3176
- ) : layoutTree.map((node) => /* @__PURE__ */ jsx("div", { children: renderNode(node) }, node.id)) });
3177
- }
3178
- function defaultPreviewCanvas() {
3179
- return /* @__PURE__ */ jsx(
3180
- "div",
3181
- {
3182
- "data-slot-id": "main",
3183
- "data-amplifyup-slot": "main",
3184
- "data-slot-source": "page",
3185
- "data-slot-empty": "true",
3186
- style: { minHeight: "50vh", width: "100%", display: "block", position: "relative" },
3187
- children: /* @__PURE__ */ jsx("div", { className: "amplifyup-slot-placeholder", children: "Drop components here" })
3188
- }
3189
- );
3190
- }
3191
- function hasAmplifyLayout(pageConfig) {
3192
- return !!(pageConfig && pageConfig.id !== "default" && Array.isArray(pageConfig.layoutTree) && pageConfig.layoutTree.length > 0);
3193
- }
3194
- function AmplifyPageContent({
3195
- fallback,
3196
- renderComponent,
3197
- pageConfig: pageConfigProp,
3198
- forceComposerPreview = false,
3199
- previewLoadingComponent,
3200
- previewEmptyComponent,
3201
- loadingComponent,
3202
- emptyComponent,
3203
- errorComponent
3204
- }) {
3205
- const client = useAmplifyUp();
3206
- const preview = forceComposerPreview || isComposerPreview();
3207
- const pageConfig = pageConfigProp ?? client.pageConfig;
3208
- const loading = pageConfigProp ? false : client.loading;
3209
- const error = pageConfigProp ? null : client.error;
3210
- const previewCanvas = previewEmptyComponent ?? defaultPreviewCanvas();
3211
- const previewLoading = previewLoadingComponent ?? previewCanvas;
3212
- if (preview) {
3213
- return /* @__PURE__ */ jsx(
3214
- AmplifyRenderer,
3215
- {
3216
- pageConfig: pageConfig ?? void 0,
3217
- renderComponent,
3218
- composerPreview: true,
3219
- loadingComponent: loadingComponent ?? previewLoading,
3220
- emptyComponent: emptyComponent ?? previewCanvas,
3221
- errorComponent: errorComponent ?? (() => previewCanvas)
3222
- }
3223
- );
3224
- }
3225
- if (loading) {
3226
- return loadingComponent ? /* @__PURE__ */ jsx(Fragment, { children: loadingComponent }) : null;
3227
- }
3228
- if (error) {
3229
- if (errorComponent) return /* @__PURE__ */ jsx(Fragment, { children: errorComponent(error) });
3230
- return fallback ? /* @__PURE__ */ jsx(Fragment, { children: fallback }) : null;
3231
- }
3232
- if (!hasAmplifyLayout(pageConfig)) {
3233
- return fallback ? /* @__PURE__ */ jsx(Fragment, { children: fallback }) : null;
3234
- }
3235
- return /* @__PURE__ */ jsx(
3236
- AmplifyRenderer,
3237
- {
3238
- pageConfig: pageConfig ?? void 0,
3239
- renderComponent,
3240
- loadingComponent,
3241
- emptyComponent,
3242
- errorComponent
3243
- }
3244
- );
3245
- }
3246
-
3247
- // src/server.tsx
3248
- async function fetchPageConfigServer(route, trackingId, preview = false, options) {
3249
- const target = resolveAmplifyUpTarget({
3250
- configTarget: options?.target
3251
- });
3252
- const { orchestratorUrl, edgeUrl } = resolveAmplifyUpUrls(target);
3253
- const previewFlag = preview || (options?.searchParams ? isPreviewRequest(options.searchParams) : false);
3254
- const fetchOrchestratorPage = async (pageRoute, isPreview) => {
3255
- const params = new URLSearchParams({
3256
- route: pageRoute,
3257
- trackingId
3258
- });
3259
- if (isPreview) params.set("preview", "true");
3260
- const url = `${orchestratorUrl}/api/layout/provider?${params.toString()}`;
3261
- try {
3262
- const res = await fetch(url, {
3263
- cache: "no-store",
3264
- headers: { Accept: "application/json" }
3265
- });
3266
- if (!res.ok) return null;
3267
- const data = await res.json();
3268
- return data.page || null;
3269
- } catch {
3270
- return null;
3271
- }
3272
- };
3273
- const result = await fetchContent({
3274
- route,
3275
- trackingId,
3276
- anonId: options?.anonId,
3277
- siteId: options?.siteId,
3278
- preview: previewFlag,
3279
- orchestratorUrl,
3280
- edgeUrl,
3281
- fetchOrchestratorPage
3282
- });
3283
- return result.pageConfig;
3284
- }
3285
- var ComponentContext = createContext(null);
3286
- function ComponentContextProvider({
3287
- children,
3288
- slots,
3289
- props,
3290
- layoutNodeId,
3291
- componentId
3292
- }) {
3293
- console.log("[ComponentContextProvider] Providing context", {
3294
- hasSlots: !!slots,
3295
- slotKeys: slots ? Object.keys(slots) : [],
3296
- slotDetails: slots ? Object.keys(slots).map((key) => ({
3297
- key,
3298
- hasContent: !!slots[key],
3299
- contentType: slots[key] ? typeof slots[key] : "null"
3300
- })) : [],
3301
- hasProps: !!props,
3302
- propKeys: props ? Object.keys(props) : [],
3303
- layoutNodeId,
3304
- componentId
3305
- });
3306
- return /* @__PURE__ */ jsx(ComponentContext.Provider, { value: { slots, props, layoutNodeId, componentId }, children });
3307
- }
3308
- function Slot({
3309
- name,
3310
- className
3311
- }) {
3312
- const context = useContext(ComponentContext);
3313
- console.log(`[Slot:${name}] Rendering slot`, {
3314
- hasContext: !!context,
3315
- availableSlotKeys: context?.slots ? Object.keys(context.slots) : [],
3316
- slotContent: context?.slots?.[name] ? "EXISTS" : "MISSING",
3317
- contextSlots: context?.slots
3318
- });
3319
- if (!context) {
3320
- console.warn(`[AmplifyUp SDK] Slot "${name}" used outside ComponentContextProvider`);
3521
+ }
3522
+ if (!pageConfig) {
3321
3523
  return null;
3322
3524
  }
3323
- const slotContent = context.slots?.[name];
3324
- const isEmpty = !slotContent;
3325
- console.log(`[Slot:${name}] Slot state`, {
3326
- isEmpty,
3327
- hasSlotContent: !!slotContent,
3328
- slotContentType: slotContent ? typeof slotContent : "null"
3329
- });
3330
- const isEditorMode = typeof window !== "undefined" && // Check for preview mode flag set by proxy
3331
- (window.__AMPLIFYUP_PREVIEW_MODE__ === true || // Check URL query params
3332
- 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)
3333
- window.self !== window.top && document.referrer && (() => {
3334
- try {
3335
- const referrerUrl = new URL(document.referrer);
3336
- return referrerUrl.hostname === "localhost" && referrerUrl.port === "5001" || referrerUrl.pathname.includes("/dashboard/composer") || referrerUrl.pathname.includes("/dashboard/routes/");
3337
- } catch {
3338
- return false;
3339
- }
3340
- })());
3341
- console.log(`[Slot:${name}] Editor mode detection`, {
3342
- isEditorMode,
3343
- isWindowDefined: typeof window !== "undefined",
3344
- previewModeFlag: typeof window !== "undefined" ? window.__AMPLIFYUP_PREVIEW_MODE__ : void 0,
3345
- urlParams: typeof window !== "undefined" ? {
3346
- preview: new URLSearchParams(window.location.search).get("preview"),
3347
- visualEditor: new URLSearchParams(window.location.search).get("visualEditor")
3348
- } : void 0,
3349
- inIframe: typeof window !== "undefined" ? window.self !== window.top : false,
3350
- referrer: typeof window !== "undefined" && document.referrer ? document.referrer : void 0
3351
- });
3352
- return /* @__PURE__ */ jsx(
3353
- "div",
3354
- {
3355
- className,
3356
- "data-slot-name": name,
3357
- "data-slot-id": name,
3358
- "data-amplifyup-slot": name,
3359
- "data-slot-empty": isEmpty ? "true" : void 0,
3360
- "data-parent-node-id": context.layoutNodeId || void 0,
3361
- "data-parent-component-id": context.componentId || void 0,
3362
- style: {
3363
- // Only add minimum height when empty (for drop target visibility)
3364
- minHeight: isEmpty ? "60px" : void 0,
3365
- // Only add position relative for overlay positioning in editor mode
3366
- position: isEditorMode ? "relative" : void 0
3367
- },
3368
- children: isEmpty ? /* @__PURE__ */ jsx(
3525
+ pageConfig.layout?.header !== false;
3526
+ pageConfig.layout?.footer !== false;
3527
+ const renderNode = (node) => {
3528
+ const zoneIdFromProps = node.componentId === "AmplifyZone" ? String(node.props?.zoneId || "") : "";
3529
+ if (node.componentId === "AmplifyZone") {
3530
+ const contentSlot = node.slots?.find((s) => s.slotId === "content") || node.slots?.[0];
3531
+ const children = Array.isArray(contentSlot?.children) ? contentSlot.children : [];
3532
+ return /* @__PURE__ */ jsx(
3369
3533
  "div",
3370
3534
  {
3371
- className: "amplifyup-slot-placeholder",
3372
- style: {
3373
- minHeight: "60px",
3374
- color: "#9ca3af",
3375
- fontSize: "14px",
3376
- pointerEvents: "none"
3377
- },
3378
- children: isEditorMode ? `Drop components here` : `Empty slot: ${name}`
3535
+ "data-node-id": node.id,
3536
+ "data-amplifyup-node": "",
3537
+ "data-amplifyup-component": "AmplifyZone",
3538
+ "data-amplifyup-zone": zoneIdFromProps || void 0,
3539
+ "data-zone-id": zoneIdFromProps || void 0,
3540
+ children: /* @__PURE__ */ jsx(
3541
+ "div",
3542
+ {
3543
+ "data-slot-id": "content",
3544
+ "data-amplifyup-slot": "content",
3545
+ "data-parent-node-id": node.id,
3546
+ "data-parent-component-id": "AmplifyZone",
3547
+ children: children.filter(Boolean).map((child) => /* @__PURE__ */ jsx(Fragment$1, { children: renderNode(child) }, child.id))
3548
+ }
3549
+ )
3379
3550
  }
3380
- ) : /* @__PURE__ */ jsxs(Fragment, { children: [
3381
- isEditorMode && /* @__PURE__ */ jsxs(
3551
+ );
3552
+ }
3553
+ let slotChildren = {};
3554
+ console.log(`[AmplifyRenderer] Rendering node ${node.id} (${node.componentId})`, {
3555
+ hasSlots: !!(node.slots && node.slots.length > 0),
3556
+ slotCount: node.slots?.length || 0,
3557
+ slots: node.slots?.map((s) => ({ slotId: s.slotId, zoneId: s.zoneId, childrenCount: s.children?.length || 0 }))
3558
+ });
3559
+ if (node.slots && node.slots.length > 0) {
3560
+ for (const slot of node.slots) {
3561
+ const slotKey = `${node.id}-${slot.slotId}`;
3562
+ let childrenToRender = [];
3563
+ console.log(`[AmplifyRenderer] Processing slot ${slot.slotId} for node ${node.id}`, {
3564
+ slotKey,
3565
+ hasZoneId: !!slot.zoneId,
3566
+ hasVariants: !!slot.variants,
3567
+ hasVariantCache: !!variantCache[slotKey],
3568
+ directChildrenCount: slot.children?.length || 0
3569
+ });
3570
+ if (slot.zoneId && slot.variants && variantCache[slotKey]) {
3571
+ childrenToRender = variantCache[slotKey].children;
3572
+ console.log(`[AmplifyRenderer] Using cached variant for slot ${slot.slotId}`, {
3573
+ variantId: variantCache[slotKey].variantId,
3574
+ childrenCount: childrenToRender.length
3575
+ });
3576
+ } else if (slot.zoneId && slot.variants) {
3577
+ const defaultVariant = slot.variants.find((v) => v.isDefault);
3578
+ childrenToRender = defaultVariant?.children || [];
3579
+ console.log(`[AmplifyRenderer] Using default variant for slot ${slot.slotId}`, {
3580
+ childrenCount: childrenToRender.length
3581
+ });
3582
+ } else {
3583
+ childrenToRender = Array.isArray(slot.children) ? slot.children : [];
3584
+ console.log(`[AmplifyRenderer] Using direct children for slot ${slot.slotId}`, {
3585
+ childrenCount: childrenToRender.length
3586
+ });
3587
+ }
3588
+ const safeChildren = Array.isArray(childrenToRender) ? childrenToRender : [];
3589
+ slotChildren[slot.slotId] = /* @__PURE__ */ jsx(
3382
3590
  "div",
3383
3591
  {
3384
- className: "amplifyup-slot-placeholder",
3385
- style: {
3386
- position: "absolute",
3387
- top: "4px",
3388
- left: "4px",
3389
- fontSize: "10px",
3390
- color: "#9ca3af",
3391
- pointerEvents: "none",
3392
- zIndex: 1,
3393
- minHeight: "auto"
3394
- },
3395
- children: [
3396
- "Slot: ",
3397
- name
3398
- ]
3399
- }
3400
- ),
3401
- slotContent
3402
- ] })
3403
- }
3404
- );
3405
- }
3406
- function isComposerEditMode() {
3407
- if (typeof window === "undefined") return false;
3408
- return isComposerPreview() && window.__AMPLIFYUP_COMPOSER_EDIT__ === true && window.__AMPLIFYUP_EVENT_SELECTION__ !== true;
3409
- }
3410
- function isLikelyNonTextFieldName(name) {
3411
- const n = name.toLowerCase();
3412
- return n.includes("href") || n.includes("url") || n.includes("src") || n.includes("image") || n.includes("icon") || n.includes("overlay") || n.includes("color");
3413
- }
3414
- function canInlineEdit(name, value) {
3415
- if (isLikelyNonTextFieldName(name)) return false;
3416
- if (value !== void 0 && value !== null && typeof value === "object") {
3417
- return false;
3418
- }
3419
- if (typeof value === "boolean") return false;
3420
- return true;
3421
- }
3422
- function useComposerEditMode() {
3423
- const [enabled, setEnabled] = useState(false);
3424
- useEffect(() => {
3425
- const sync = () => setEnabled(isComposerEditMode());
3426
- sync();
3427
- window.addEventListener("amplifyup:composer-edit", sync);
3428
- return () => window.removeEventListener("amplifyup:composer-edit", sync);
3429
- }, []);
3430
- return enabled;
3431
- }
3432
- function useFieldOverlay(layoutNodeId, name, source) {
3433
- const [overlay, setOverlay] = useState(void 0);
3434
- useEffect(() => {
3435
- const onPatch = (event) => {
3436
- const detail = event.detail || {};
3437
- if (detail.fieldName !== name) return;
3438
- if (detail.layoutNodeId && layoutNodeId && String(detail.layoutNodeId) !== String(layoutNodeId)) {
3439
- return;
3592
+ "data-slot-id": slot.slotId,
3593
+ "data-amplifyup-slot": slot.slotId,
3594
+ "data-zone-id": slot.zoneId || void 0,
3595
+ "data-parent-node-id": node.id,
3596
+ "data-parent-component-id": node.componentId,
3597
+ children: safeChildren.filter(Boolean).map((child) => /* @__PURE__ */ jsx(Fragment$1, { children: renderNode(child) }, child.id))
3598
+ },
3599
+ slot.slotId
3600
+ );
3601
+ console.log(`[AmplifyRenderer] Created slot content for ${slot.slotId}`, {
3602
+ slotId: slot.slotId,
3603
+ renderedChildrenCount: childrenToRender.length
3604
+ });
3440
3605
  }
3441
- setOverlay(detail.value);
3442
- };
3443
- window.addEventListener("amplifyup:field-patch", onPatch);
3444
- return () => window.removeEventListener("amplifyup:field-patch", onPatch);
3445
- }, [layoutNodeId, name]);
3446
- return overlay !== void 0 ? overlay : source;
3447
- }
3448
- function commitComposerField(layoutNodeId, componentId, name, value) {
3449
- if (typeof window === "undefined" || window.parent === window) return;
3450
- window.parent.postMessage(
3451
- {
3452
- type: "AMPLIFYUP_FIELD_COMMIT",
3453
- layoutNodeId,
3454
- componentId,
3455
- fieldName: name,
3456
- value
3457
- },
3458
- "*"
3459
- );
3460
- }
3461
- function ComposerInlineField({
3462
- name,
3463
- value,
3464
- fallback,
3465
- className,
3466
- render,
3467
- layoutNodeId,
3468
- componentId
3469
- }) {
3470
- const [editing, setEditing] = useState(false);
3471
- const elRef = useRef(null);
3472
- const text = formatFieldValue(value);
3473
- const fallbackText = typeof fallback === "string" || typeof fallback === "number" ? String(fallback) : "";
3474
- const display = text || fallbackText;
3475
- const showRendered = !!render && !editing;
3476
- useEffect(() => {
3477
- const el = elRef.current;
3478
- if (!el || showRendered) return;
3479
- if (document.activeElement === el) return;
3480
- const next = display || "";
3481
- if (el.textContent !== next) el.textContent = next;
3482
- }, [display, showRendered]);
3483
- useEffect(() => {
3484
- if (!editing || !elRef.current) return;
3485
- const el = elRef.current;
3486
- el.textContent = display || "";
3487
- el.focus();
3488
- const range = document.createRange();
3489
- range.selectNodeContents(el);
3490
- const sel = window.getSelection();
3491
- sel?.removeAllRanges();
3492
- sel?.addRange(range);
3493
- }, [editing]);
3494
- const finishEdit = () => {
3495
- const raw = (elRef.current?.innerText ?? "").replace(/\u00a0/g, " ").replace(/\n+$/g, "");
3496
- const next = raw.trim() === "" ? "" : raw;
3497
- setEditing(false);
3498
- if (next === text) return;
3499
- if (!text && next === fallbackText) return;
3500
- commitComposerField(layoutNodeId, componentId, name, next);
3606
+ }
3607
+ const slotsToPass = Object.keys(slotChildren).length > 0 ? slotChildren : void 0;
3608
+ return /* @__PURE__ */ jsx("div", { "data-node-id": node.id, "data-amplifyup-node": "", children: /* @__PURE__ */ jsx(
3609
+ ComponentRenderBoundary,
3610
+ {
3611
+ componentId: node.componentId,
3612
+ nodeId: node.id,
3613
+ children: /* @__PURE__ */ jsx(
3614
+ LiveNodeRender,
3615
+ {
3616
+ nodeId: node.id,
3617
+ componentId: node.componentId,
3618
+ props: node.props || {},
3619
+ slots: slotsToPass,
3620
+ renderComponent
3621
+ }
3622
+ )
3623
+ }
3624
+ ) });
3501
3625
  };
3626
+ const rawTree = pageConfig.layoutTree;
3627
+ const layoutTree = Array.isArray(rawTree) ? rawTree : rawTree && typeof rawTree === "object" && rawTree.componentId ? [rawTree] : [];
3628
+ if (layoutTree.length === 0) {
3629
+ 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." }) }) });
3630
+ }
3631
+ return /* @__PURE__ */ jsx("main", { children: composerPreview || isComposerPreview() ? /* @__PURE__ */ jsx(
3632
+ "div",
3633
+ {
3634
+ "data-slot-id": "main",
3635
+ "data-amplifyup-slot": "main",
3636
+ "data-slot-source": "page",
3637
+ "data-slot-empty": layoutTree.length === 0 ? "true" : void 0,
3638
+ children: layoutTree.map((node) => /* @__PURE__ */ jsx("div", { children: renderNode(node) }, node.id))
3639
+ }
3640
+ ) : layoutTree.map((node) => /* @__PURE__ */ jsx("div", { children: renderNode(node) }, node.id)) });
3641
+ }
3642
+ function defaultPreviewCanvas() {
3502
3643
  return /* @__PURE__ */ jsx(
3503
- "span",
3644
+ "div",
3504
3645
  {
3505
- ref: elRef,
3506
- className,
3507
- "data-amplifyup-field": name,
3508
- "data-amplifyup-node-id": layoutNodeId || void 0,
3509
- contentEditable: !showRendered,
3510
- suppressContentEditableWarning: true,
3511
- role: "textbox",
3512
- tabIndex: 0,
3513
- onMouseDown: (event) => {
3514
- event.stopPropagation();
3515
- },
3516
- onClick: (event) => {
3517
- const link = event.target?.closest?.("a");
3518
- if (link) event.preventDefault();
3519
- if (render && isComposerEditMode()) {
3520
- setEditing(true);
3521
- }
3522
- },
3523
- onFocus: () => {
3524
- if (!isComposerEditMode()) return;
3525
- if (render) setEditing(true);
3526
- },
3527
- onBlur: finishEdit,
3528
- onKeyDown: (event) => {
3529
- event.stopPropagation();
3530
- if (event.key === "Enter" && !event.shiftKey) {
3531
- event.preventDefault();
3532
- event.currentTarget.blur();
3533
- }
3534
- if (event.key === "Escape") {
3535
- event.preventDefault();
3536
- if (elRef.current) elRef.current.textContent = display || "";
3537
- setEditing(false);
3538
- event.currentTarget.blur();
3539
- }
3540
- },
3541
- style: {
3542
- cursor: "text",
3543
- outline: "1px dashed color-mix(in srgb, currentColor 40%, transparent)",
3544
- outlineOffset: "2px",
3545
- minWidth: "1ch",
3546
- display: render ? void 0 : "inline"
3547
- },
3548
- children: showRendered ? value != null && value !== "" ? render(value) : fallback ?? display : null
3646
+ "data-slot-id": "main",
3647
+ "data-amplifyup-slot": "main",
3648
+ "data-slot-source": "page",
3649
+ "data-slot-empty": "true",
3650
+ style: { minHeight: "50vh", width: "100%", display: "block", position: "relative" },
3651
+ children: /* @__PURE__ */ jsx("div", { className: "amplifyup-slot-placeholder", children: "Drop components here" })
3549
3652
  }
3550
3653
  );
3551
3654
  }
3552
- function formatFieldValue(value) {
3553
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
3554
- return String(value);
3555
- }
3556
- if (Array.isArray(value)) {
3557
- const parts = value.map((item) => {
3558
- if (typeof item === "string") return item;
3559
- if (item && typeof item === "object" && "children" in item && Array.isArray(item.children)) {
3560
- return item.children.map((c) => typeof c?.text === "string" ? c.text : "").join("");
3561
- }
3562
- return "";
3563
- }).filter(Boolean);
3564
- if (parts.length > 0) return parts.join(" ");
3565
- }
3566
- if (value && typeof value === "object") {
3567
- return "";
3568
- }
3569
- return "";
3655
+ function hasAmplifyLayout(pageConfig) {
3656
+ return !!(pageConfig && pageConfig.id !== "default" && Array.isArray(pageConfig.layoutTree) && pageConfig.layoutTree.length > 0);
3570
3657
  }
3571
- function Field({
3572
- name,
3658
+ function AmplifyPageContent({
3573
3659
  fallback,
3574
- className,
3575
- render
3660
+ renderComponent,
3661
+ pageConfig: pageConfigProp,
3662
+ forceComposerPreview = false,
3663
+ previewLoadingComponent,
3664
+ previewEmptyComponent,
3665
+ loadingComponent,
3666
+ emptyComponent,
3667
+ errorComponent
3576
3668
  }) {
3577
- const context = useContext(ComponentContext);
3578
- const composerEdit = useComposerEditMode();
3579
- const fieldValue = useFieldOverlay(
3580
- context?.layoutNodeId,
3581
- name,
3582
- context?.props?.[name]
3583
- );
3584
- if (!context) {
3585
- console.warn(`[AmplifyUp SDK] Field "${name}" used outside ComponentContextProvider`);
3586
- return fallback ? /* @__PURE__ */ jsx(Fragment, { children: fallback }) : null;
3587
- }
3588
- if (composerEdit && canInlineEdit(name, fieldValue)) {
3669
+ const client = useAmplifyUp();
3670
+ const preview = forceComposerPreview || isComposerPreview();
3671
+ const pageConfig = pageConfigProp ?? client.pageConfig;
3672
+ const loading = pageConfigProp ? false : client.loading;
3673
+ const error = pageConfigProp ? null : client.error;
3674
+ const previewCanvas = previewEmptyComponent ?? defaultPreviewCanvas();
3675
+ const previewLoading = previewLoadingComponent ?? previewCanvas;
3676
+ if (preview) {
3589
3677
  return /* @__PURE__ */ jsx(
3590
- ComposerInlineField,
3678
+ AmplifyRenderer,
3591
3679
  {
3592
- name,
3593
- value: fieldValue,
3594
- fallback,
3595
- className,
3596
- render,
3597
- layoutNodeId: context.layoutNodeId,
3598
- componentId: context.componentId
3680
+ pageConfig: pageConfig ?? void 0,
3681
+ renderComponent,
3682
+ composerPreview: true,
3683
+ loadingComponent: loadingComponent ?? previewLoading,
3684
+ emptyComponent: emptyComponent ?? previewCanvas,
3685
+ errorComponent: errorComponent ?? (() => previewCanvas)
3599
3686
  }
3600
3687
  );
3601
3688
  }
3602
- if (fieldValue === void 0 || fieldValue === null) {
3603
- return fallback ? /* @__PURE__ */ jsx("span", { className, children: fallback }) : null;
3604
- }
3605
- if (render) {
3606
- return /* @__PURE__ */ jsx("span", { className, children: render(fieldValue) });
3607
- }
3608
- const text = formatFieldValue(fieldValue);
3609
- if (!text) {
3610
- return fallback ? /* @__PURE__ */ jsx("span", { className, children: fallback }) : null;
3611
- }
3612
- return /* @__PURE__ */ jsx("span", { className, children: text });
3613
- }
3614
- function markdownToHtml(markdown) {
3615
- try {
3616
- const result = marked.parse(markdown, { async: false });
3617
- return typeof result === "string" ? result : "";
3618
- } catch {
3619
- return markdown;
3689
+ if (loading) {
3690
+ return loadingComponent ? /* @__PURE__ */ jsx(Fragment, { children: loadingComponent }) : null;
3620
3691
  }
3621
- }
3622
- function RichText({
3623
- name,
3624
- fallback,
3625
- className,
3626
- as: Tag = "div"
3627
- }) {
3628
- const context = useContext(ComponentContext);
3629
- const composerEdit = useComposerEditMode();
3630
- const fieldValue = useFieldOverlay(
3631
- context?.layoutNodeId,
3632
- name,
3633
- context?.props?.[name]
3634
- );
3635
- if (!context) {
3636
- console.warn(`[AmplifyUp SDK] RichText "${name}" used outside ComponentContextProvider`);
3692
+ if (error) {
3693
+ if (errorComponent) return /* @__PURE__ */ jsx(Fragment, { children: errorComponent(error) });
3637
3694
  return fallback ? /* @__PURE__ */ jsx(Fragment, { children: fallback }) : null;
3638
3695
  }
3639
- if (composerEdit && canInlineEdit(name, fieldValue)) {
3640
- return /* @__PURE__ */ jsx(
3641
- ComposerInlineField,
3642
- {
3643
- name,
3644
- value: fieldValue,
3645
- fallback,
3646
- className,
3647
- layoutNodeId: context.layoutNodeId,
3648
- componentId: context.componentId
3649
- }
3650
- );
3651
- }
3652
- if (fieldValue === void 0 || fieldValue === null || fieldValue === "") {
3653
- return fallback ? /* @__PURE__ */ jsx(Tag, { className, children: fallback }) : null;
3696
+ if (!hasAmplifyLayout(pageConfig)) {
3697
+ return fallback ? /* @__PURE__ */ jsx(Fragment, { children: fallback }) : null;
3654
3698
  }
3655
- let html = "";
3656
- if (typeof fieldValue === "string") {
3657
- const trimmed = fieldValue.trim();
3658
- if (trimmed.startsWith("<") && trimmed.includes(">")) {
3659
- html = fieldValue;
3660
- } else {
3661
- html = markdownToHtml(fieldValue);
3699
+ return /* @__PURE__ */ jsx(
3700
+ AmplifyRenderer,
3701
+ {
3702
+ pageConfig: pageConfig ?? void 0,
3703
+ renderComponent,
3704
+ loadingComponent,
3705
+ emptyComponent,
3706
+ errorComponent
3662
3707
  }
3663
- } else {
3664
- const text = formatFieldValue(fieldValue);
3665
- html = text ? markdownToHtml(text) : "";
3666
- }
3667
- if (!html) {
3668
- return fallback ? /* @__PURE__ */ jsx(Tag, { className, children: fallback }) : null;
3669
- }
3670
- return /* @__PURE__ */ jsx(Tag, { className, dangerouslySetInnerHTML: { __html: html } });
3708
+ );
3709
+ }
3710
+
3711
+ // src/server.tsx
3712
+ async function fetchPageConfigServer(route, trackingId, preview = false, options) {
3713
+ const target = resolveAmplifyUpTarget({
3714
+ configTarget: options?.target
3715
+ });
3716
+ const { orchestratorUrl, edgeUrl } = resolveAmplifyUpUrls(target);
3717
+ const previewFlag = preview || (options?.searchParams ? isPreviewRequest(options.searchParams) : false);
3718
+ const fetchOrchestratorPage = async (pageRoute, isPreview) => {
3719
+ const params = new URLSearchParams({
3720
+ route: pageRoute,
3721
+ trackingId
3722
+ });
3723
+ if (isPreview) params.set("preview", "true");
3724
+ const url = `${orchestratorUrl}/api/layout/provider?${params.toString()}`;
3725
+ try {
3726
+ const res = await fetch(url, {
3727
+ cache: "no-store",
3728
+ headers: { Accept: "application/json" }
3729
+ });
3730
+ if (!res.ok) return null;
3731
+ const data = await res.json();
3732
+ return data.page || null;
3733
+ } catch {
3734
+ return null;
3735
+ }
3736
+ };
3737
+ const result = await fetchContent({
3738
+ route,
3739
+ trackingId,
3740
+ anonId: options?.anonId,
3741
+ siteId: options?.siteId,
3742
+ preview: previewFlag,
3743
+ orchestratorUrl,
3744
+ edgeUrl,
3745
+ fetchOrchestratorPage
3746
+ });
3747
+ return result.pageConfig;
3671
3748
  }
3672
3749
  var usePathname = null;
3673
3750
  if (typeof window !== "undefined") {
@@ -3826,6 +3903,6 @@ function useAmplifyUp() {
3826
3903
  return context;
3827
3904
  }
3828
3905
 
3829
- export { AmplifyPageContent, AmplifyRenderer, AmplifyUpProvider, ComponentContextProvider, Field, RichText, Slot, fetchPageConfigServer, isComposerPreview, isPreviewRequest, useAmplifyUp };
3906
+ export { AmplifyPageContent, AmplifyRenderer, AmplifyUpProvider, ComponentContextProvider, Field, RichText, Slot, fetchPageConfigServer, isComposerPreview, isPreviewRequest, useAmplifyUp, useComponentProps, useLiveComposerProps };
3830
3907
  //# sourceMappingURL=react.mjs.map
3831
3908
  //# sourceMappingURL=react.mjs.map