@contentstack/live-preview-utils
Version:
Contentstack provides the Live Preview SDK to establish a communication channel between the various Contentstack SDKs and your website, transmitting live changes to the preview pane.
270 lines (269 loc) • 13.3 kB
JavaScript
import "../../chunk-5WRI5ZAA.js";
// src/visualBuilder/utils/updateFocussedState.ts
import { VisualBuilder } from "../index.js";
import { extractDetailsFromCslp } from "../../cslp/index.js";
import { getAddInstanceButtons } from "../generators/generateAddInstanceButtons.js";
import {
addFocusOverlay,
hideFocusOverlay
} from "../generators/generateOverlay.js";
import { hideHoverOutline } from "../listeners/mouseHover.js";
import { getEntryPermissionsCached } from "./getEntryPermissionsCached.js";
import {
LIVE_PREVIEW_OUTLINE_WIDTH_IN_PX,
RIGHT_EDGE_BUFFER,
TOOLBAR_EDGE_BUFFER,
TOP_EDGE_BUFFER
} from "./constants.js";
import { FieldSchemaMap } from "./fieldSchemaMap.js";
import getChildrenDirection from "./getChildrenDirection.js";
import { getPsuedoEditableElementStyles } from "./getPsuedoEditableStylesElement.js";
import { isFieldDisabled } from "./isFieldDisabled.js";
function positionToolbar({
focusedToolbar,
selectedElementDimension
}) {
if (focusedToolbar) {
const targetElementRightEdgeOffset = window.scrollX + window.innerWidth - selectedElementDimension.left;
const distanceFromTop = selectedElementDimension.top + window.scrollY - TOOLBAR_EDGE_BUFFER;
const adjustedDistanceFromTop = selectedElementDimension.top + window.scrollY < TOP_EDGE_BUFFER ? distanceFromTop + selectedElementDimension.height + TOP_EDGE_BUFFER : distanceFromTop;
const distanceFromLeft = selectedElementDimension.left - LIVE_PREVIEW_OUTLINE_WIDTH_IN_PX;
const adjustedDistanceFromLeft = Math.max(
distanceFromLeft,
TOOLBAR_EDGE_BUFFER
);
if (targetElementRightEdgeOffset < RIGHT_EDGE_BUFFER && (focusedToolbar.style.justifyContent !== "flex-end" || focusedToolbar.style.left !== `${selectedElementDimension.right + LIVE_PREVIEW_OUTLINE_WIDTH_IN_PX}px`)) {
focusedToolbar.style.justifyContent = "flex-end";
focusedToolbar.style.left = `${selectedElementDimension.right + LIVE_PREVIEW_OUTLINE_WIDTH_IN_PX}px`;
} else if (focusedToolbar.style.justifyContent !== "flex-start" || focusedToolbar.style.left !== `${adjustedDistanceFromLeft}px`) {
focusedToolbar.style.justifyContent = "flex-start";
focusedToolbar.style.left = `${adjustedDistanceFromLeft}px`;
}
if (focusedToolbar.style.top !== `${adjustedDistanceFromTop}px`) {
focusedToolbar.style.top = `${adjustedDistanceFromTop}px`;
}
}
}
async function updateFocussedState({
editableElement,
visualBuilderContainer,
overlayWrapper,
focusedToolbar,
resizeObserver
}) {
var _a, _b;
let previousSelectedEditableDOM = VisualBuilder.VisualBuilderGlobalState.value.previousSelectedEditableDOM;
if (!visualBuilderContainer || !editableElement || !previousSelectedEditableDOM || !overlayWrapper) {
return;
}
const previousSelectedElementCslp = (editableElement == null ? void 0 : editableElement.getAttribute("data-cslp")) || "";
const previousSelectedElementCslpUniqueId = previousSelectedEditableDOM == null ? void 0 : previousSelectedEditableDOM.getAttribute("data-cslp-unique-id");
const newPreviousSelectedElement = document.querySelector(
`[data-cslp-unique-id="${previousSelectedElementCslpUniqueId}"]`
) || document.querySelector(`[data-cslp="${previousSelectedElementCslp}"]`);
if (!newPreviousSelectedElement && resizeObserver) {
hideFocusOverlay({
visualBuilderOverlayWrapper: overlayWrapper,
focusedToolbar,
visualBuilderContainer,
resizeObserver,
noTrigger: true
});
return;
}
if (newPreviousSelectedElement !== previousSelectedEditableDOM) {
previousSelectedEditableDOM = newPreviousSelectedElement;
VisualBuilder.VisualBuilderGlobalState.value.previousSelectedEditableDOM = previousSelectedEditableDOM;
}
const cslp = (editableElement == null ? void 0 : editableElement.getAttribute("data-cslp")) || "";
const fieldMetadata = extractDetailsFromCslp(cslp);
hideHoverOutline(visualBuilderContainer);
const fieldSchema = await FieldSchemaMap.getFieldSchema(
fieldMetadata.content_type_uid,
fieldMetadata.fieldPath
);
const entryAcl = await getEntryPermissionsCached({
entryUid: fieldMetadata.entry_uid,
contentTypeUid: fieldMetadata.content_type_uid,
locale: fieldMetadata.locale
});
const { isDisabled } = isFieldDisabled(
fieldSchema,
{ editableElement, fieldMetadata },
entryAcl
);
addFocusOverlay(previousSelectedEditableDOM, overlayWrapper, isDisabled);
const psuedoEditableElement = visualBuilderContainer.querySelector(
".visual-builder__pseudo-editable-element"
);
if (psuedoEditableElement) {
const styles = getPsuedoEditableElementStyles(editableElement);
const styleString = Object.entries(styles).reduce(
(acc, [key, value]) => {
return `${acc}${key}:${value};`;
},
""
);
psuedoEditableElement.style.cssText = styleString;
psuedoEditableElement.style.visibility = "visible";
}
const targetElementDimension = editableElement.getBoundingClientRect();
if (targetElementDimension.width && targetElementDimension.height) {
const selectedElement = VisualBuilder.VisualBuilderGlobalState.value.previousSelectedEditableDOM;
if (!selectedElement) return;
positionToolbar({
focusedToolbar,
selectedElementDimension: selectedElement.getBoundingClientRect()
});
}
const buttons = getAddInstanceButtons(visualBuilderContainer);
const parentCslpValue = (_b = (_a = fieldMetadata.multipleFieldMetadata) == null ? void 0 : _a.parentDetails) == null ? void 0 : _b.parentCslpValue;
if (buttons && parentCslpValue && buttons.length > 1 && buttons[0] && buttons[1]) {
const [previousButton, nextButton] = buttons;
const direction = getChildrenDirection(
editableElement,
parentCslpValue
);
const targetDOMDimension = editableElement.getBoundingClientRect();
if (direction === "horizontal") {
const middleHeight = targetDOMDimension.top + (targetDOMDimension.bottom - targetDOMDimension.top) / 2 + window.scrollY;
previousButton.style.left = `${targetDOMDimension.left}px`;
previousButton.style.top = `${middleHeight}px`;
nextButton.style.left = `${targetDOMDimension.right}px`;
nextButton.style.top = `${middleHeight}px`;
} else if (direction === "vertical") {
const middleWidth = targetDOMDimension.left + (targetDOMDimension.right - targetDOMDimension.left) / 2;
previousButton.style.left = `${middleWidth}px`;
previousButton.style.top = `${targetDOMDimension.top + window.scrollY}px`;
nextButton.style.left = `${middleWidth}px`;
nextButton.style.top = `${targetDOMDimension.bottom + window.scrollY}px`;
}
}
}
function updateFocussedStateOnMutation(focusOverlayWrapper, focusedToolbar, visualBuilderContainer, resizeObserver) {
if (!focusOverlayWrapper) return;
let selectedElement = VisualBuilder.VisualBuilderGlobalState.value.previousSelectedEditableDOM;
if (!selectedElement) return;
const selectedElementCslp = selectedElement == null ? void 0 : selectedElement.getAttribute("data-cslp");
const selectedElementCslpUniqueId = selectedElement == null ? void 0 : selectedElement.getAttribute(
"data-cslp-unique-id"
);
const newSelectedElement = document.querySelector(
`[data-cslp-unique-id="${selectedElementCslpUniqueId}"]`
) || document.querySelector(`[data-cslp="${selectedElementCslp}"]`);
if (!newSelectedElement && resizeObserver) {
hideFocusOverlay({
visualBuilderOverlayWrapper: focusOverlayWrapper,
focusedToolbar,
visualBuilderContainer,
resizeObserver,
noTrigger: true
});
return;
}
if (newSelectedElement !== selectedElement) {
selectedElement = newSelectedElement;
VisualBuilder.VisualBuilderGlobalState.value.previousSelectedEditableDOM = selectedElement;
}
const selectedElementDimension = selectedElement.getBoundingClientRect();
const focusOutline = focusOverlayWrapper.querySelector(
".visual-builder__overlay--outline"
);
if (focusOutline) {
const focusOutlineDimension = focusOutline.getBoundingClientRect();
if (!isSameRect(selectedElementDimension, focusOutlineDimension)) {
focusOutline.style.top = `${selectedElementDimension.top + window.scrollY}px`;
focusOutline.style.left = `${selectedElementDimension.left}px`;
focusOutline.style.width = `${selectedElementDimension.width}px`;
focusOutline.style.height = `${selectedElementDimension.height}px`;
}
}
const focusedOverlayTop = focusOverlayWrapper.querySelector(
".visual-builder__overlay--top"
);
const focusedOverlayBottom = focusOverlayWrapper.querySelector(
".visual-builder__overlay--bottom"
);
const focusedOverlayLeft = focusOverlayWrapper.querySelector(
".visual-builder__overlay--left"
);
const focusedOverlayRight = focusOverlayWrapper.querySelector(
".visual-builder__overlay--right"
);
const distanceFromTop = selectedElementDimension.top + window.scrollY;
if (focusedOverlayTop) {
const dimension = focusedOverlayTop.getBoundingClientRect();
if (dimension.height !== distanceFromTop) {
focusedOverlayTop.style.height = `calc(${distanceFromTop}px)`;
}
}
if (focusedOverlayBottom) {
const dimension = focusedOverlayBottom.getBoundingClientRect();
if (dimension.top !== selectedElementDimension.bottom || dimension.height !== window.document.body.scrollHeight - selectedElementDimension.bottom - window.scrollY) {
focusedOverlayBottom.style.top = `${selectedElementDimension.bottom + window.scrollY}px`;
focusedOverlayBottom.style.height = `${window.document.body.scrollHeight - selectedElementDimension.bottom - window.scrollY}px`;
}
}
if (focusedOverlayLeft) {
const dimension = focusedOverlayLeft.getBoundingClientRect();
if (dimension.top + window.scrollY !== distanceFromTop || dimension.height !== selectedElementDimension.height || dimension.width !== selectedElementDimension.left) {
focusedOverlayLeft.style.top = `${distanceFromTop}px`;
focusedOverlayLeft.style.height = `${selectedElementDimension.height}px`;
focusedOverlayLeft.style.width = `${selectedElementDimension.left}px`;
}
}
if (focusedOverlayRight) {
const dimension = focusedOverlayRight.getBoundingClientRect();
if (dimension.left !== selectedElementDimension.right || dimension.top + window.scrollY !== distanceFromTop || dimension.height !== selectedElementDimension.height || dimension.width !== document.documentElement.clientWidth - selectedElementDimension.right) {
focusedOverlayRight.style.left = `${selectedElementDimension.right}px`;
focusedOverlayRight.style.top = `${distanceFromTop}px`;
focusedOverlayRight.style.height = `${selectedElementDimension.height}px`;
focusedOverlayRight.style.width = `${document.documentElement.clientWidth - selectedElementDimension.right}px`;
}
}
if (focusedToolbar) {
const targetElementRightEdgeOffset = window.scrollX + window.innerWidth - selectedElementDimension.left;
const distanceFromTop2 = selectedElementDimension.top + window.scrollY - TOOLBAR_EDGE_BUFFER;
const adjustedDistanceFromTop = selectedElementDimension.top + window.scrollY < TOP_EDGE_BUFFER ? distanceFromTop2 + selectedElementDimension.height + TOP_EDGE_BUFFER : distanceFromTop2;
const distanceFromLeft = selectedElementDimension.left - LIVE_PREVIEW_OUTLINE_WIDTH_IN_PX;
const adjustedDistanceFromLeft = Math.max(
distanceFromLeft,
TOOLBAR_EDGE_BUFFER
);
if (targetElementRightEdgeOffset < RIGHT_EDGE_BUFFER && (focusedToolbar.style.justifyContent !== "flex-end" || focusedToolbar.style.left !== `${selectedElementDimension.right + LIVE_PREVIEW_OUTLINE_WIDTH_IN_PX}px`)) {
focusedToolbar.style.justifyContent = "flex-end";
focusedToolbar.style.left = `${selectedElementDimension.right + LIVE_PREVIEW_OUTLINE_WIDTH_IN_PX}px`;
} else if (focusedToolbar.style.justifyContent !== "flex-start" || focusedToolbar.style.left !== `${adjustedDistanceFromLeft}px`) {
focusedToolbar.style.justifyContent = "flex-start";
focusedToolbar.style.left = `${adjustedDistanceFromLeft}px`;
}
if (focusedToolbar.style.top !== `${adjustedDistanceFromTop}px`) {
focusedToolbar.style.top = `${adjustedDistanceFromTop}px`;
}
}
if (visualBuilderContainer) {
const psuedoEditableElement = visualBuilderContainer.querySelector(
".visual-builder__pseudo-editable-element"
);
const editableElement = selectedElement;
const styles = getPsuedoEditableElementStyles(editableElement);
const styleString = Object.entries(styles).reduce(
(acc, [key, value]) => {
return `${acc}${key}:${value};`;
},
""
);
if (psuedoEditableElement && (psuedoEditableElement.style.cssText !== styleString || psuedoEditableElement.style.visibility !== "visible")) {
psuedoEditableElement.style.cssText = styleString;
psuedoEditableElement.style.visibility = "visible";
}
}
}
function isSameRect(rect1, rect2) {
return rect1.top === rect2.top && rect1.left === rect2.left && rect1.width === rect2.width && rect1.height === rect2.height;
}
export {
updateFocussedState,
updateFocussedStateOnMutation
};
//# sourceMappingURL=updateFocussedState.js.map