diff --git a/src/visualBuilder/components/Tooltip.tsx b/src/visualBuilder/components/Tooltip.tsx index 1e708d02..3d6f48b9 100644 --- a/src/visualBuilder/components/Tooltip.tsx +++ b/src/visualBuilder/components/Tooltip.tsx @@ -89,7 +89,7 @@ const Tooltip = ({ children, content, placement = 'top-start' }: TooltipProps) = if (side === 'top' || side === 'bottom') { // For top/bottom placements, center the arrow horizontally - arrowElement.style.left = `${tooltipRect.width / 2 - 4}px`; // 4px = half arrow width + arrowElement.style.left = `${14}px`; // 4px = half arrow width if (arrowY != null) { arrowElement.style.top = `${arrowY}px`; } diff --git a/src/visualBuilder/components/fieldLabelWrapper.tsx b/src/visualBuilder/components/fieldLabelWrapper.tsx index b6ca5886..dc01c89c 100644 --- a/src/visualBuilder/components/fieldLabelWrapper.tsx +++ b/src/visualBuilder/components/fieldLabelWrapper.tsx @@ -18,6 +18,14 @@ import { getEntryPermissionsCached } from "../utils/getEntryPermissionsCached"; import { ContentTypeIcon } from "./icons"; import { ToolbarTooltip } from "./Tooltip"; +interface ReferenceParentMap { + [entryUid: string]: { + contentTypeUid: string; + contentTypeTitle: string; + referenceFieldName: string; + }[] +} + async function getFieldDisplayNames(fieldMetadata: CslpData[]) { const result = await visualBuilderPostMessage?.send<{ [k: string]: string; @@ -26,13 +34,30 @@ async function getFieldDisplayNames(fieldMetadata: CslpData[]) { } async function getContentTypeName(contentTypeUid: string) { - const result = await visualBuilderPostMessage?.send<{ - [k: string]: string; - }>(VisualBuilderPostMessageEvents.GET_CONTENT_TYPE_NAME, { - content_type_uid: contentTypeUid, - }); - return result; + try { + const result = await visualBuilderPostMessage?.send<{ + contentTypeName: string; + }>(VisualBuilderPostMessageEvents.GET_CONTENT_TYPE_NAME, { + content_type_uid: contentTypeUid, + }); + return result?.contentTypeName; + } catch(e) { + console.warn("[getFieldLabelWrapper] Error getting content type name", e); + return ""; + } +} + +async function getReferenceParentMap() { + try { + const result = await visualBuilderPostMessage?.send(VisualBuilderPostMessageEvents.REFERENCE_MAP, {}) ?? {}; + return result; + } catch(e) { + console.warn("[getFieldLabelWrapper] Error getting reference parent map", e); + return {}; + } + } + interface FieldLabelWrapperProps { fieldMetadata: CslpData; eventDetails: VisualBuilderCslpEventDetails; @@ -49,6 +74,7 @@ interface ICurrentField { isVariant: boolean; isReference: boolean; referenceFieldName: string; + parentContentTypeName: string; isEmbedded: boolean; } @@ -65,12 +91,13 @@ function FieldLabelWrapperComponent( isVariant: false, isReference: false, referenceFieldName: "", + parentContentTypeName: "", isEmbedded: false, }); const [displayNames, setDisplayNames] = useState>( {} ); - const [displayNamesLoading, setDisplayNamesLoading] = useState(true); + const [dataLoading, setDataLoading] = useState(true); const [error, setError] = useState(false); const [isDropdownOpen, setIsDropdownOpen] = useState(false); @@ -82,7 +109,7 @@ function FieldLabelWrapperComponent( useEffect(() => { const fetchData = async () => { - setDisplayNamesLoading(true); + setDataLoading(true); const allPaths = uniqBy( [ props.fieldMetadata, @@ -99,12 +126,34 @@ function FieldLabelWrapperComponent( props.fieldMetadata.fieldPath ) ]); - // const contentTypeName = await getContentTypeName( - // props.fieldMetadata.content_type_uid - // ); + const contentTypeName = await getContentTypeName( + props.fieldMetadata.content_type_uid + ); + const referenceParentMap = await getReferenceParentMap(); + const entryUid = props.fieldMetadata.entry_uid; + + const referenceData = referenceParentMap[entryUid]; + const isReference = !!referenceData; + + let referenceFieldName = referenceData ? referenceData[0].referenceFieldName : ""; + let parentContentTypeName = referenceData ? referenceData[0].contentTypeTitle : ""; + + if(isReference) { + const domAncestor = eventDetails.editableElement.closest(`[data-cslp]:not([data-cslp^="${props.fieldMetadata.content_type_uid}"])`); + if(domAncestor) { + const domAncestorCslp = domAncestor.getAttribute("data-cslp"); + const domAncestorDetails = extractDetailsFromCslp(domAncestorCslp!); + const domAncestorContentTypeUid = domAncestorDetails.content_type_uid; + const domAncestorContentParent = referenceData?.find(data => data.contentTypeUid === domAncestorContentTypeUid); + if(domAncestorContentParent) { + referenceFieldName = domAncestorContentParent.referenceFieldName; + parentContentTypeName = domAncestorContentParent.contentTypeTitle; + } + } + } if (hasPostMessageError(displayNames) || !fieldSchema) { - setDisplayNamesLoading(false); + setDataLoading(false); setError(true); return; @@ -130,7 +179,7 @@ function FieldLabelWrapperComponent( setCurrentField({ text: currentFieldDisplayName, - contentTypeName: 'Page CT', + contentTypeName: contentTypeName ?? "", icon: fieldDisabled ? (
), - isReference: false, + isReference, isEmbedded: false, prefixIcon: getFieldIcon(fieldSchema), disabled: fieldDisabled, - referenceFieldName: "Reference Field", + referenceFieldName, + parentContentTypeName, isVariant: isVariant, }); @@ -159,11 +209,15 @@ function FieldLabelWrapperComponent( setDisplayNames(displayNames); } if (Object.keys(displayNames || {})?.length === allPaths.length) { - setDisplayNamesLoading(false); + setDataLoading(false); } }; - fetchData(); + try { + fetchData(); + } catch(e) { + console.warn("[getFieldLabelWrapper] Error fetching field label data", e); + } }, [props]); const onParentPathClick = (cslp: string) => { @@ -177,7 +231,7 @@ function FieldLabelWrapperComponent( function getCurrentFieldIcon() { if (error) { return null; - } else if (displayNamesLoading) { + } else if (dataLoading) { return ; } else { return currentField.icon; @@ -193,7 +247,7 @@ function FieldLabelWrapperComponent( ] )} > - +
{ - currentField.isReference && !displayNamesLoading && !error ? + currentField.isReference && !dataLoading && !error ?
: null } - {!displayNamesLoading && !error && } - {currentField.contentTypeName && !displayNamesLoading && !error ? ( + {!dataLoading && !error && } + {currentField.contentTypeName && !dataLoading && !error ? (
() => { diff --git a/src/visualBuilder/listeners/mouseHover.ts b/src/visualBuilder/listeners/mouseHover.ts index ccd7bcc5..3978d820 100644 --- a/src/visualBuilder/listeners/mouseHover.ts +++ b/src/visualBuilder/listeners/mouseHover.ts @@ -26,7 +26,7 @@ const config = Config.get(); export interface HandleMouseHoverParams extends Pick< EventListenerHandlerParams, - "event" | "overlayWrapper" | "visualBuilderContainer" + "event" | "overlayWrapper" | "visualBuilderContainer" | "focusedToolbar" | "resizeObserver" > { customCursor: HTMLDivElement | null; } @@ -200,15 +200,6 @@ function isFieldPathDropdown(target: HTMLElement): boolean { return target.classList.contains("visual-builder__focused-toolbar__field-label-wrapper") || target.classList.contains("visual-builder__focused-toolbar__field-label-wrapper__current-field"); } -export function syncReferenceMap() { - const referenceParentMap = VisualBuilder.VisualBuilderGlobalState.value.referenceParentMap; - // Only sync on first hover - if(!referenceParentMap) { - return; - } - visualBuilderPostMessage?.send(VisualBuilderPostMessageEvents.SYNC_REFERENCE_MAP); -} - const throttledMouseHover = throttle(async (params: HandleMouseHoverParams) => { const eventDetails = getCsDataOfElement(params.event); const eventTarget = params.event.target as HTMLElement | null; @@ -233,6 +224,16 @@ const throttledMouseHover = throttle(async (params: HandleMouseHoverParams) => { isFieldPathDropdown(eventTarget) ) { showOutline(); + showHoverToolbar({ + event: params.event, + overlayWrapper: params.overlayWrapper, + visualBuilderContainer: params.visualBuilderContainer, + previousSelectedEditableDOM: + VisualBuilder.VisualBuilderGlobalState.value + .previousSelectedEditableDOM, + focusedToolbar: params.focusedToolbar, + resizeObserver: params.resizeObserver, + }); } if (!config?.collab.enable) { resetCustomCursor(params.customCursor); @@ -370,6 +371,16 @@ const throttledMouseHover = throttle(async (params: HandleMouseHoverParams) => { fieldPath, fieldMetadata, }); + showHoverToolbar({ + event: params.event, + overlayWrapper: params.overlayWrapper, + visualBuilderContainer: params.visualBuilderContainer, + previousSelectedEditableDOM: + VisualBuilder.VisualBuilderGlobalState.value + .previousSelectedEditableDOM, + focusedToolbar: params.focusedToolbar, + resizeObserver: params.resizeObserver, + }); } if ( diff --git a/src/visualBuilder/utils/types/postMessage.types.ts b/src/visualBuilder/utils/types/postMessage.types.ts index 2b2d3230..25037e58 100644 --- a/src/visualBuilder/utils/types/postMessage.types.ts +++ b/src/visualBuilder/utils/types/postMessage.types.ts @@ -44,7 +44,6 @@ export enum VisualBuilderPostMessageEvents { SEND_VARIANT_AND_LOCALE = "send-variant-and-locale", GET_CONTENT_TYPE_NAME = "get-content-type-name", REFERENCE_MAP = "get-reference-map", - SYNC_REFERENCE_MAP = "sync-reference-map", COLLAB_ENABLE = "collab-enable", COLLAB_DATA_UPDATE = "collab-data-update", COLLAB_DISABLE = "collab-disable",