Files
klz-cables.com/.pnpm-store/v10/files/91/3f6f98473d01c32592a7d73ab2f7251ecdfb4f7a7beae38d0714d968bc03441df3db4c7075df99593846c19f7106d214296cfc1b70613237b2da5eeec16287
Marc Mintel 5397309103
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Failing after 34s
Build & Deploy / 🏗️ Build (push) Has started running
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Smoke Test (push) Has been cancelled
Build & Deploy / ⚡ Lighthouse (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
fix(products): fix breadcrumbs and product filtering (backport from main)
2026-02-24 16:04:21 +01:00

225 lines
7.2 KiB
Plaintext

'use client';
import { jsx as _jsx } from "react/jsx-runtime";
import { DndContext } from '@dnd-kit/core';
import React, { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';
import { usePopupWindow } from '../../hooks/usePopupWindow.js';
import { useDocumentInfo } from '../../providers/DocumentInfo/index.js';
import { usePreferences } from '../../providers/Preferences/index.js';
import { formatAbsoluteURL } from '../../utilities/formatAbsoluteURL.js';
import { customCollisionDetection } from './collisionDetection.js';
import { LivePreviewContext } from './context.js';
import { sizeReducer } from './sizeReducer.js';
export const LivePreviewProvider = ({
breakpoints: incomingBreakpoints,
children,
isLivePreviewEnabled,
isLivePreviewing: incomingIsLivePreviewing,
isPreviewEnabled,
previewURL: previewURLFromProps,
typeofLivePreviewURL,
url: urlFromProps
}) => {
const [previewWindowType, setPreviewWindowType] = useState('iframe');
const [isLivePreviewing, setIsLivePreviewing] = useState(incomingIsLivePreviewing);
const breakpoints = useMemo(() => [...(incomingBreakpoints || []), {
name: 'responsive',
height: '100%',
label: 'Responsive',
width: '100%'
}], [incomingBreakpoints]);
const [url, setURL] = useState('');
const [previewURL, setPreviewURL] = useState(previewURLFromProps);
const {
isPopupOpen,
openPopupWindow,
popupRef
} = usePopupWindow({
eventType: 'payload-live-preview',
url
});
const [appIsReady, setAppIsReady] = useState(false);
const [listeningForMessages, setListeningForMessages] = useState(false);
const {
collectionSlug,
globalSlug
} = useDocumentInfo();
const isFirstRender = useRef(true);
const {
setPreference
} = usePreferences();
const iframeRef = React.useRef(null);
const [loadedURL, setLoadedURL] = useState();
const [zoom, setZoom] = useState(1);
const [position, setPosition] = useState({
x: 0,
y: 0
});
const [size, setSize] = React.useReducer(sizeReducer, {
height: 0,
width: 0
});
const [measuredDeviceSize, setMeasuredDeviceSize] = useState({
height: 0,
width: 0
});
const [breakpoint, setBreakpoint] = React.useState('responsive');
/**
* A "middleware" callback fn that does some additional work before `setURL`.
* This is what we provide through context, bc it:
* - ensures the URL is absolute
* - resets `appIsReady` to `false` while the new URL is loading
*/
const setLivePreviewURL = useCallback(_incomingURL => {
let incomingURL;
if (typeof _incomingURL === 'string') {
incomingURL = formatAbsoluteURL(_incomingURL);
}
if (!incomingURL) {
setIsLivePreviewing(false);
}
if (incomingURL !== url) {
setAppIsReady(false);
setURL(incomingURL);
}
}, [url]);
/**
* `url` needs to be relative to the window, which cannot be done on initial render.
*/
useEffect(() => {
if (typeof urlFromProps === 'string') {
setURL(formatAbsoluteURL(urlFromProps));
}
}, [urlFromProps]);
// The toolbar needs to freely drag and drop around the page
const handleDragEnd = ev => {
// only update position if the toolbar is completely within the preview area
// otherwise reset it back to the previous position
// TODO: reset to the nearest edge of the preview area
if (ev.over && ev.over.id === 'live-preview-area') {
const newPos = {
x: position.x + ev.delta.x,
y: position.y + ev.delta.y
};
setPosition(newPos);
} else {
// reset
}
};
const setWidth = useCallback(width => {
setSize({
type: 'width',
value: width
});
}, [setSize]);
const setHeight = useCallback(height => {
setSize({
type: 'height',
value: height
});
}, [setSize]);
// explicitly set new width and height when as new breakpoints are selected
// exclude `custom` breakpoint as it is handled by the `setWidth` and `setHeight` directly
useEffect(() => {
const foundBreakpoint = breakpoints?.find(bp => bp.name === breakpoint);
if (foundBreakpoint && breakpoint !== 'responsive' && breakpoint !== 'custom' && typeof foundBreakpoint?.width === 'number' && typeof foundBreakpoint?.height === 'number') {
setSize({
type: 'reset',
value: {
height: foundBreakpoint.height,
width: foundBreakpoint.width
}
});
}
}, [breakpoint, breakpoints]);
/**
* Receive the `ready` message from the popup window
* This indicates that the app is ready to receive `window.postMessage` events
* This is also the only cross-origin way of detecting when a popup window has loaded
* Unlike iframe elements which have an `onLoad` handler, there is no way to access `window.open` on popups
*/
useEffect(() => {
const handleMessage = event => {
if (url?.startsWith(event.origin) && event.data && typeof event.data === 'object' && event.data.type === 'payload-live-preview') {
if (event.data.ready) {
setAppIsReady(true);
}
}
};
window.addEventListener('message', handleMessage);
setListeningForMessages(true);
return () => {
window.removeEventListener('message', handleMessage);
};
}, [url, listeningForMessages]);
const handleWindowChange = useCallback(type => {
setAppIsReady(false);
setPreviewWindowType(type);
if (type === 'popup') {
openPopupWindow();
}
}, [openPopupWindow]);
// when the user closes the popup window, switch back to the iframe
// the `usePopupWindow` reports the `isPopupOpen` state for us to use here
useEffect(() => {
const newPreviewWindowType = isPopupOpen ? 'popup' : 'iframe';
if (newPreviewWindowType !== previewWindowType) {
handleWindowChange('iframe');
}
}, [previewWindowType, isPopupOpen, handleWindowChange]);
useEffect(() => {
if (isFirstRender.current) {
isFirstRender.current = false;
return;
}
void setPreference(collectionSlug ? `collection-${collectionSlug}` : `global-${globalSlug}`, {
editViewType: isLivePreviewing ? 'live-preview' : 'default'
}, true);
}, [isLivePreviewing, setPreference, collectionSlug, globalSlug]);
const dndContextID = useId();
return /*#__PURE__*/_jsx(LivePreviewContext, {
value: {
appIsReady,
breakpoint,
breakpoints,
iframeRef,
isLivePreviewEnabled,
isLivePreviewing,
isPopupOpen,
isPreviewEnabled,
listeningForMessages,
loadedURL,
measuredDeviceSize,
openPopupWindow,
popupRef,
previewURL,
previewWindowType,
setAppIsReady,
setBreakpoint,
setHeight,
setIsLivePreviewing,
setLoadedURL,
setMeasuredDeviceSize,
setPreviewURL,
setPreviewWindowType: handleWindowChange,
setSize,
setToolbarPosition: setPosition,
setURL: setLivePreviewURL,
setWidth,
setZoom,
size,
toolbarPosition: position,
typeofLivePreviewURL,
url,
zoom
},
children: /*#__PURE__*/_jsx(DndContext, {
collisionDetection: customCollisionDetection,
// Provide stable ID to fix hydration issues: https://github.com/clauderic/dnd-kit/issues/926
id: dndContextID,
onDragEnd: handleDragEnd,
children: children
})
});
};
//# sourceMappingURL=index.js.map