@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.
481 lines (480 loc) • 19 kB
JavaScript
import "../../chunk-5WRI5ZAA.js";
// src/visualBuilder/components/FieldToolbar.tsx
import getChildrenDirection from "../utils/getChildrenDirection.js";
import {
ALLOWED_MODAL_EDITABLE_FIELD,
ALLOWED_REPLACE_FIELDS
} from "../utils/constants.js";
import { getFieldType } from "../utils/getFieldType.js";
import {
handleDeleteInstance,
handleMoveInstance
} from "../utils/instanceHandlers.js";
import visualBuilderPostMessage from "../utils/visualBuilderPostMessage.js";
import { FieldDataType } from "../utils/types/index.types.js";
import { VisualBuilderPostMessageEvents } from "../utils/types/postMessage.types.js";
import {
CaretIcon,
DeleteIcon,
MoveLeftIcon,
MoveRightIcon,
ReplaceAssetIcon
} from "./icons/index.js";
import { fieldIcons } from "./icons/fields/index.js";
import classNames from "classnames";
import { visualBuilderStyles } from "../visualBuilder.style.js";
import CommentIcon from "./CommentIcon.js";
import { useEffect, useState, useRef } from "preact/compat";
import { FieldSchemaMap } from "../utils/fieldSchemaMap.js";
import { isFieldDisabled } from "../utils/isFieldDisabled.js";
import { FormIcon } from "./icons/index.js";
import { getDOMEditStack } from "../utils/getCsDataOfElement.js";
import { VariantIcon } from "./icons/variant.js";
import {
BASE_VARIANT_STATUS,
getFieldVariantStatus,
VariantRevertDropdown
} from "./FieldRevert/FieldRevertComponent.js";
import { LoadingIcon } from "./icons/loading.js";
import { FieldLocationAppList } from "./FieldLocationAppList.js";
import { FieldLocationIcon } from "./FieldLocationIcon.js";
import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
var TOOLTIP_TOP_EDGE_BUFFER = 96;
function handleReplaceAsset(fieldMetadata) {
visualBuilderPostMessage?.send(
VisualBuilderPostMessageEvents.OPEN_ASSET_MODAL,
{
fieldMetadata
}
);
}
function handleReplaceReference(fieldMetadata) {
const isMultipleInstance = fieldMetadata.multipleFieldMetadata.index > -1 && fieldMetadata.fieldPathWithIndex === fieldMetadata.multipleFieldMetadata.parentDetails?.parentPath;
const entryPath = isMultipleInstance ? fieldMetadata.instance.fieldPathWithIndex : fieldMetadata.fieldPathWithIndex;
visualBuilderPostMessage?.send(
VisualBuilderPostMessageEvents.OPEN_REFERENCE_MODAL,
{
entry_uid: fieldMetadata.entry_uid,
content_type_uid: fieldMetadata.content_type_uid,
locale: fieldMetadata.locale,
fieldPath: fieldMetadata.fieldPath,
fieldPathWithIndex: fieldMetadata.fieldPathWithIndex,
entryPath
}
);
}
function handleEdit(fieldMetadata) {
visualBuilderPostMessage?.send(
VisualBuilderPostMessageEvents.OPEN_FIELD_EDIT_MODAL,
{ fieldMetadata }
);
}
function handleFormFieldFocus(eventDetails) {
const { editableElement } = eventDetails;
return visualBuilderPostMessage?.send(
VisualBuilderPostMessageEvents.FOCUS_FIELD,
{
DOMEditStack: getDOMEditStack(editableElement),
toggleVisibility: true
}
);
}
function FieldToolbarComponent(props) {
const {
eventDetails,
isVariant: isVariantOrParentOfVariant,
entryPermissions
} = props;
const { fieldMetadata, editableElement: targetElement } = eventDetails;
const [isFormLoading, setIsFormLoading] = useState(false);
const [fieldLocationData, setFieldLocationData] = useState(null);
const [displayAllApps, setDisplayAllApps] = useState(false);
const moreButtonRef = useRef(null);
const toolbarRef = useRef(null);
const [appListPosition, setAppListPosition] = useState(
"right"
);
const parentPath = fieldMetadata?.multipleFieldMetadata?.parentDetails?.parentCslpValue || "";
const isVariant = !!fieldMetadata?.variant || isVariantOrParentOfVariant;
const direction = getChildrenDirection(targetElement, parentPath);
const [fieldSchema, setFieldSchema] = useState(
null
);
const [fieldVariantStatus, setFieldVariantStatus] = useState(BASE_VARIANT_STATUS);
const [isOpenVariantRevert, setIsOpenVariantRevert] = useState(false);
let isModalEditable = false;
let isReplaceAllowed = false;
let isMultiple = false;
let Icon = null;
let fieldType = null;
let isWholeMultipleField = false;
const APP_LIST_MIN_WIDTH = 230;
let disableFieldActions = false;
if (fieldSchema) {
const { isDisabled } = isFieldDisabled(
fieldSchema,
{
editableElement: targetElement,
fieldMetadata
},
entryPermissions
);
disableFieldActions = isDisabled;
fieldType = getFieldType(fieldSchema);
Icon = fieldIcons[fieldType];
isMultiple = fieldSchema.multiple || false;
if (fieldType === FieldDataType.REFERENCE)
isMultiple = fieldSchema.field_metadata.ref_multiple;
isWholeMultipleField = isMultiple && (fieldMetadata.fieldPathWithIndex === fieldMetadata.instance.fieldPathWithIndex || fieldMetadata.multipleFieldMetadata?.index === -1);
isModalEditable = ALLOWED_MODAL_EDITABLE_FIELD.includes(fieldType) && !isWholeMultipleField;
isReplaceAllowed = ALLOWED_REPLACE_FIELDS.includes(fieldType) && !isWholeMultipleField;
}
const domEditStack = getDOMEditStack(eventDetails.editableElement);
const invertTooltipPosition = targetElement.getBoundingClientRect().top <= TOOLTIP_TOP_EDGE_BUFFER;
const handleMoreIconClick = () => {
if (toolbarRef.current) {
const rect = toolbarRef.current.getBoundingClientRect();
const spaceRight = window.innerWidth - rect.right;
const spaceLeft = rect.left;
let position = "";
if (spaceRight < APP_LIST_MIN_WIDTH) {
position = "left";
} else if (spaceRight > APP_LIST_MIN_WIDTH) {
position = "right";
} else {
position = spaceRight > spaceLeft ? "right" : "left";
}
setAppListPosition(position);
}
setDisplayAllApps(!displayAllApps);
};
const editButton = Icon ? /* @__PURE__ */ jsx(
"button",
{
"data-testid": "visual-builder__focused-toolbar__multiple-field-toolbar__edit-button",
className: classNames(
"visual-builder__button visual-builder__button--secondary visual-builder__button--edit",
visualBuilderStyles()["visual-builder__button"],
visualBuilderStyles()["visual-builder__button--secondary"],
visualBuilderStyles()["visual-builder__button--edit"],
visualBuilderStyles()["visual-builder__tooltip"],
{
"visual-builder__tooltip--bottom": invertTooltipPosition,
[visualBuilderStyles()["visual-builder__tooltip--bottom"]]: invertTooltipPosition
}
),
"data-tooltip": "Edit",
onClick: (e) => {
e.preventDefault();
e.stopPropagation();
handleEdit(fieldMetadata);
},
disabled: disableFieldActions,
children: /* @__PURE__ */ jsx(Icon, {})
}
) : null;
const replaceButton = fieldType ? /* @__PURE__ */ jsx(
"button",
{
className: classNames(
"visual-builder__replace-button visual-builder__button visual-builder__button--secondary",
visualBuilderStyles()["visual-builder__button"],
visualBuilderStyles()["visual-builder__button--secondary"],
visualBuilderStyles()["visual-builder__tooltip"],
{
"visual-builder__tooltip--bottom": invertTooltipPosition,
[visualBuilderStyles()["visual-builder__tooltip--bottom"]]: invertTooltipPosition
}
),
"data-tooltip": "Replace",
"data-testid": `visual-builder-replace-${fieldType}`,
onClick: (e) => {
e.stopPropagation();
e.preventDefault();
if (fieldType === FieldDataType.REFERENCE) {
handleReplaceReference(fieldMetadata);
return;
} else if (fieldType === FieldDataType.FILE) {
handleReplaceAsset(fieldMetadata);
return;
}
},
disabled: disableFieldActions,
children: /* @__PURE__ */ jsx(ReplaceAssetIcon, {})
}
) : null;
const formButton = /* @__PURE__ */ jsx(
"button",
{
className: classNames(
"visual-builder__replace-button visual-builder__button visual-builder__button--secondary",
visualBuilderStyles()["visual-builder__button"],
visualBuilderStyles()["visual-builder__button--secondary"],
visualBuilderStyles()["visual-builder__tooltip"],
{
"visual-builder__tooltip--bottom": invertTooltipPosition,
[visualBuilderStyles()["visual-builder__tooltip--bottom"]]: invertTooltipPosition
},
{
[visualBuilderStyles()["visual-builder__button--comment-loader"]]: isFormLoading,
"visual-builder__button--comment-loader": isFormLoading
}
),
"data-tooltip": "Form",
"data-testid": `visual-builder-form`,
onClick: async (e) => {
e.preventDefault();
e.stopPropagation();
setIsFormLoading(true);
try {
await handleFormFieldFocus(eventDetails);
} finally {
setIsFormLoading(false);
}
},
disabled: isFormLoading,
children: isFormLoading ? /* @__PURE__ */ jsx(LoadingIcon, {}) : /* @__PURE__ */ jsx(FormIcon, {})
}
);
const toggleVariantDropdown = () => {
setIsOpenVariantRevert(!isOpenVariantRevert);
};
const closeVariantDropdown = () => {
setIsOpenVariantRevert(false);
};
const variantButton = /* @__PURE__ */ jsxs(
"button",
{
className: classNames(
"visual-builder__variant-button visual-builder__button visual-builder__button--secondary",
visualBuilderStyles()["visual-builder__button"],
visualBuilderStyles()["visual-builder__button--secondary"],
visualBuilderStyles()["visual-builder__tooltip"],
visualBuilderStyles()["visual-builder__variant-button"],
{
"visual-builder__tooltip--bottom": invertTooltipPosition,
[visualBuilderStyles()["visual-builder__tooltip--bottom"]]: invertTooltipPosition
}
),
"data-tooltip": "Variant Revert",
"data-testid": `visual-builder-canvas-variant-revert`,
onClick: toggleVariantDropdown,
children: [
/* @__PURE__ */ jsx(VariantIcon, {}),
/* @__PURE__ */ jsx(CaretIcon, { open: isOpenVariantRevert })
]
}
);
const totalElementCount = targetElement?.parentNode?.childElementCount ?? 1;
const indexOfElement = fieldMetadata?.multipleFieldMetadata?.index;
const disableMoveLeft = indexOfElement === 0;
const disableMoveRight = indexOfElement === totalElementCount - 1;
useEffect(() => {
async function fetchFieldSchema() {
const fieldSchema2 = await FieldSchemaMap.getFieldSchema(
fieldMetadata.content_type_uid,
fieldMetadata.fieldPath
);
if (fieldSchema2) {
setFieldSchema(fieldSchema2);
}
const variantStatus = await getFieldVariantStatus(fieldMetadata);
setFieldVariantStatus(variantStatus ?? BASE_VARIANT_STATUS);
}
fetchFieldSchema();
}, [fieldMetadata]);
useEffect(() => {
const event = visualBuilderPostMessage?.on(
VisualBuilderPostMessageEvents.DELETE_INSTANCE,
(args) => {
if (args.data?.path === fieldMetadata.instance.fieldPathWithIndex) {
props.hideOverlay();
}
}
);
return () => {
event?.unregister();
};
}, []);
useEffect(() => {
const fetchFieldLocationData = async () => {
try {
const event = await visualBuilderPostMessage?.send(VisualBuilderPostMessageEvents.FIELD_LOCATION_DATA, {
domEditStack: getDOMEditStack(eventDetails.editableElement)
});
setFieldLocationData(event);
} catch (error) {
console.error("Error fetching field location data:", error);
}
};
fetchFieldLocationData();
}, [eventDetails.editableElement]);
const multipleFieldToolbarButtonClasses = classNames(
"visual-builder__button visual-builder__button--secondary",
visualBuilderStyles()["visual-builder__button"],
visualBuilderStyles()["visual-builder__button--secondary"],
visualBuilderStyles()["visual-builder__tooltip"],
{
"visual-builder__tooltip--bottom": invertTooltipPosition,
[visualBuilderStyles()["visual-builder__tooltip--bottom"]]: invertTooltipPosition
}
);
return /* @__PURE__ */ jsxs(
"div",
{
className: classNames(
"visual-builder__field-toolbar-container",
visualBuilderStyles()["visual-builder__field-toolbar-container"]
),
children: [
/* @__PURE__ */ jsx(
"div",
{
className: classNames(
"visual-builder__focused-toolbar__multiple-field-toolbar",
visualBuilderStyles()["visual-builder__focused-toolbar__multiple-field-toolbar"]
),
"data-testid": "visual-builder__focused-toolbar__multiple-field-toolbar",
children: /* @__PURE__ */ jsx(
"div",
{
className: classNames(
"visual-builder__focused-toolbar__button-group",
visualBuilderStyles()["visual-builder__focused-toolbar__button-group"]
),
children: /* @__PURE__ */ jsxs(Fragment, { children: [
isVariant ? /* @__PURE__ */ jsx(
VariantRevertDropdown,
{
fieldDataName: fieldMetadata.fieldPathWithIndex,
fieldMetadata,
variantStatus: fieldVariantStatus,
isOpen: isOpenVariantRevert,
closeDropdown: closeVariantDropdown,
invertTooltipPosition,
toggleVariantDropdown,
disabled: disableFieldActions
}
) : null,
isMultiple && !isWholeMultipleField ? /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(
"button",
{
"data-testid": "visual-builder__focused-toolbar__multiple-field-toolbar__move-left-button",
className: multipleFieldToolbarButtonClasses,
"data-tooltip": direction === "vertical" ? "Move up" : "Move left",
onClick: (e) => {
e.preventDefault();
e.stopPropagation();
handleMoveInstance(
fieldMetadata,
"previous"
);
},
disabled: disableFieldActions || disableMoveLeft,
children: /* @__PURE__ */ jsx(
MoveLeftIcon,
{
className: classNames({
"visual-builder__rotate--90": direction === "vertical",
[visualBuilderStyles()["visual-builder__rotate--90"]]: direction === "vertical"
}),
disabled: disableFieldActions || disableMoveLeft
}
)
}
),
/* @__PURE__ */ jsx(
"button",
{
"data-testid": "visual-builder__focused-toolbar__multiple-field-toolbar__move-right-button",
className: multipleFieldToolbarButtonClasses,
"data-tooltip": direction === "vertical" ? "Move down" : "Move right",
onClick: (e) => {
e.preventDefault();
e.stopPropagation();
handleMoveInstance(
fieldMetadata,
"next"
);
},
disabled: disableFieldActions || disableMoveRight,
children: /* @__PURE__ */ jsx(
MoveRightIcon,
{
className: classNames({
"visual-builder__rotate--90": direction === "vertical",
[visualBuilderStyles()["visual-builder__rotate--90"]]: direction === "vertical"
}),
disabled: disableFieldActions || disableMoveRight
}
)
}
),
isModalEditable ? editButton : null,
formButton,
isReplaceAllowed ? replaceButton : null,
/* @__PURE__ */ jsx(
"button",
{
"data-testid": "visual-builder__focused-toolbar__multiple-field-toolbar__delete-button",
className: multipleFieldToolbarButtonClasses,
"data-tooltip": "Delete",
onClick: (e) => {
e.preventDefault();
e.stopPropagation();
handleDeleteInstance(fieldMetadata);
},
disabled: disableFieldActions,
children: /* @__PURE__ */ jsx(DeleteIcon, {})
}
)
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
isModalEditable ? editButton : null,
isReplaceAllowed ? replaceButton : null,
formButton,
fieldSchema ? /* @__PURE__ */ jsx(
CommentIcon,
{
fieldMetadata,
fieldSchema,
invertTooltipPosition
}
) : null
] }),
/* @__PURE__ */ jsx(
FieldLocationIcon,
{
fieldLocationData,
multipleFieldToolbarButtonClasses,
handleMoreIconClick,
moreButtonRef,
toolbarRef,
domEditStack
}
)
] })
}
)
}
),
displayAllApps && /* @__PURE__ */ jsx(
FieldLocationAppList,
{
toolbarRef,
apps: fieldLocationData?.apps || [],
position: appListPosition,
domEditStack,
setDisplayAllApps,
displayAllApps
}
)
]
}
);
}
var FieldToolbar_default = FieldToolbarComponent;
export {
FieldToolbar_default as default
};
//# sourceMappingURL=FieldToolbar.js.map