@amplifyup/sdk 0.1.27 → 0.1.28

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