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