Skip to content

Commit bfd84b7

Browse files
authored
Merge pull request #453 from contentstack/VE-6698-reference-map-sync
[HoverToolbar]: Handling postMessage for ReferenceParentMap and rendering changes
2 parents 19f865a + bab4171 commit bfd84b7

5 files changed

Lines changed: 100 additions & 45 deletions

File tree

src/visualBuilder/components/Tooltip.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ const Tooltip = ({ children, content, placement = 'top-start' }: TooltipProps) =
8989

9090
if (side === 'top' || side === 'bottom') {
9191
// For top/bottom placements, center the arrow horizontally
92-
arrowElement.style.left = `${tooltipRect.width / 2 - 4}px`; // 4px = half arrow width
92+
arrowElement.style.left = `${14}px`; // 4px = half arrow width
9393
if (arrowY != null) {
9494
arrowElement.style.top = `${arrowY}px`;
9595
}

src/visualBuilder/components/fieldLabelWrapper.tsx

Lines changed: 77 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ import { getEntryPermissionsCached } from "../utils/getEntryPermissionsCached";
1818
import { ContentTypeIcon } from "./icons";
1919
import { ToolbarTooltip } from "./Tooltip";
2020

21+
interface ReferenceParentMap {
22+
[entryUid: string]: {
23+
contentTypeUid: string;
24+
contentTypeTitle: string;
25+
referenceFieldName: string;
26+
}[]
27+
}
28+
2129
async function getFieldDisplayNames(fieldMetadata: CslpData[]) {
2230
const result = await visualBuilderPostMessage?.send<{
2331
[k: string]: string;
@@ -26,13 +34,30 @@ async function getFieldDisplayNames(fieldMetadata: CslpData[]) {
2634
}
2735

2836
async function getContentTypeName(contentTypeUid: string) {
29-
const result = await visualBuilderPostMessage?.send<{
30-
[k: string]: string;
31-
}>(VisualBuilderPostMessageEvents.GET_CONTENT_TYPE_NAME, {
32-
content_type_uid: contentTypeUid,
33-
});
34-
return result;
37+
try {
38+
const result = await visualBuilderPostMessage?.send<{
39+
contentTypeName: string;
40+
}>(VisualBuilderPostMessageEvents.GET_CONTENT_TYPE_NAME, {
41+
content_type_uid: contentTypeUid,
42+
});
43+
return result?.contentTypeName;
44+
} catch(e) {
45+
console.warn("[getFieldLabelWrapper] Error getting content type name", e);
46+
return "";
47+
}
48+
}
49+
50+
async function getReferenceParentMap() {
51+
try {
52+
const result = await visualBuilderPostMessage?.send<ReferenceParentMap>(VisualBuilderPostMessageEvents.REFERENCE_MAP, {}) ?? {};
53+
return result;
54+
} catch(e) {
55+
console.warn("[getFieldLabelWrapper] Error getting reference parent map", e);
56+
return {};
57+
}
58+
3559
}
60+
3661
interface FieldLabelWrapperProps {
3762
fieldMetadata: CslpData;
3863
eventDetails: VisualBuilderCslpEventDetails;
@@ -49,6 +74,7 @@ interface ICurrentField {
4974
isVariant: boolean;
5075
isReference: boolean;
5176
referenceFieldName: string;
77+
parentContentTypeName: string;
5278
isEmbedded: boolean;
5379
}
5480

@@ -65,12 +91,13 @@ function FieldLabelWrapperComponent(
6591
isVariant: false,
6692
isReference: false,
6793
referenceFieldName: "",
94+
parentContentTypeName: "",
6895
isEmbedded: false,
6996
});
7097
const [displayNames, setDisplayNames] = useState<Record<string, string>>(
7198
{}
7299
);
73-
const [displayNamesLoading, setDisplayNamesLoading] = useState(true);
100+
const [dataLoading, setDataLoading] = useState(true);
74101
const [error, setError] = useState(false);
75102
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
76103

@@ -82,7 +109,7 @@ function FieldLabelWrapperComponent(
82109

83110
useEffect(() => {
84111
const fetchData = async () => {
85-
setDisplayNamesLoading(true);
112+
setDataLoading(true);
86113
const allPaths = uniqBy(
87114
[
88115
props.fieldMetadata,
@@ -99,12 +126,34 @@ function FieldLabelWrapperComponent(
99126
props.fieldMetadata.fieldPath
100127
)
101128
]);
102-
// const contentTypeName = await getContentTypeName(
103-
// props.fieldMetadata.content_type_uid
104-
// );
129+
const contentTypeName = await getContentTypeName(
130+
props.fieldMetadata.content_type_uid
131+
);
132+
const referenceParentMap = await getReferenceParentMap();
133+
const entryUid = props.fieldMetadata.entry_uid;
134+
135+
const referenceData = referenceParentMap[entryUid];
136+
const isReference = !!referenceData;
137+
138+
let referenceFieldName = referenceData ? referenceData[0].referenceFieldName : "";
139+
let parentContentTypeName = referenceData ? referenceData[0].contentTypeTitle : "";
140+
141+
if(isReference) {
142+
const domAncestor = eventDetails.editableElement.closest(`[data-cslp]:not([data-cslp^="${props.fieldMetadata.content_type_uid}"])`);
143+
if(domAncestor) {
144+
const domAncestorCslp = domAncestor.getAttribute("data-cslp");
145+
const domAncestorDetails = extractDetailsFromCslp(domAncestorCslp!);
146+
const domAncestorContentTypeUid = domAncestorDetails.content_type_uid;
147+
const domAncestorContentParent = referenceData?.find(data => data.contentTypeUid === domAncestorContentTypeUid);
148+
if(domAncestorContentParent) {
149+
referenceFieldName = domAncestorContentParent.referenceFieldName;
150+
parentContentTypeName = domAncestorContentParent.contentTypeTitle;
151+
}
152+
}
153+
}
105154

106155
if (hasPostMessageError(displayNames) || !fieldSchema) {
107-
setDisplayNamesLoading(false);
156+
setDataLoading(false);
108157
setError(true);
109158

110159
return;
@@ -130,7 +179,7 @@ function FieldLabelWrapperComponent(
130179

131180
setCurrentField({
132181
text: currentFieldDisplayName,
133-
contentTypeName: 'Page CT',
182+
contentTypeName: contentTypeName ?? "",
134183
icon: fieldDisabled ? (
135184
<div
136185
className={classNames(
@@ -147,23 +196,28 @@ function FieldLabelWrapperComponent(
147196
) : (
148197
<></>
149198
),
150-
isReference: false,
199+
isReference,
151200
isEmbedded: false,
152201
prefixIcon: getFieldIcon(fieldSchema),
153202
disabled: fieldDisabled,
154-
referenceFieldName: "Reference Field",
203+
referenceFieldName,
204+
parentContentTypeName,
155205
isVariant: isVariant,
156206
});
157207

158208
if (displayNames) {
159209
setDisplayNames(displayNames);
160210
}
161211
if (Object.keys(displayNames || {})?.length === allPaths.length) {
162-
setDisplayNamesLoading(false);
212+
setDataLoading(false);
163213
}
164214
};
165215

166-
fetchData();
216+
try {
217+
fetchData();
218+
} catch(e) {
219+
console.warn("[getFieldLabelWrapper] Error fetching field label data", e);
220+
}
167221
}, [props]);
168222

169223
const onParentPathClick = (cslp: string) => {
@@ -177,7 +231,7 @@ function FieldLabelWrapperComponent(
177231
function getCurrentFieldIcon() {
178232
if (error) {
179233
return null;
180-
} else if (displayNamesLoading) {
234+
} else if (dataLoading) {
181235
return <LoadingIcon />;
182236
} else {
183237
return currentField.icon;
@@ -193,7 +247,7 @@ function FieldLabelWrapperComponent(
193247
]
194248
)}
195249
>
196-
<ToolbarTooltip data={{contentTypeName: currentField.contentTypeName, referenceFieldName: currentField.referenceFieldName}} disabled={!currentField.isReference}>
250+
<ToolbarTooltip data={{contentTypeName: currentField.parentContentTypeName, referenceFieldName: currentField.referenceFieldName}} disabled={!currentField.isReference || isDropdownOpen}>
197251
<div
198252
className={classNames(
199253
"visual-builder__focused-toolbar__field-label-wrapper",
@@ -235,10 +289,10 @@ function FieldLabelWrapperComponent(
235289
"visual-builder__button-error"
236290
]
237291
)}
238-
disabled={displayNamesLoading}
292+
disabled={dataLoading}
239293
>
240294
{
241-
currentField.isReference && !displayNamesLoading && !error ?
295+
currentField.isReference && !dataLoading && !error ?
242296
<div
243297
className={classNames(
244298
"visual-builder__reference-icon-container",
@@ -260,8 +314,8 @@ function FieldLabelWrapperComponent(
260314
<CaretRightIcon />
261315
</div> : null
262316
}
263-
{!displayNamesLoading && !error && <ContentTypeIcon />}
264-
{currentField.contentTypeName && !displayNamesLoading && !error ? (
317+
{!dataLoading && !error && <ContentTypeIcon />}
318+
{currentField.contentTypeName && !dataLoading && !error ? (
265319
<div
266320
className={classNames(
267321
"visual-builder__focused-toolbar__text",

src/visualBuilder/listeners/index.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { throttle } from "lodash-es";
21
import { VisualBuilder } from "..";
32
import handleBuilderInteraction from "./mouseClick";
43
import handleMouseHover, {
@@ -37,16 +36,8 @@ const eventHandlers = {
3736
overlayWrapper: params.overlayWrapper,
3837
visualBuilderContainer: params.visualBuilderContainer,
3938
customCursor: params.customCursor,
40-
});
41-
showHoverToolbar({
42-
event: event,
43-
overlayWrapper: params.overlayWrapper,
44-
visualBuilderContainer: params.visualBuilderContainer,
45-
previousSelectedEditableDOM:
46-
VisualBuilder.VisualBuilderGlobalState.value
47-
.previousSelectedEditableDOM,
48-
focusedToolbar: params.focusedToolbar,
4939
resizeObserver: params.resizeObserver,
40+
focusedToolbar: params.focusedToolbar,
5041
});
5142
},
5243
mouseleave: (params: AddEventListenersParams) => () => {

src/visualBuilder/listeners/mouseHover.ts

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const config = Config.get();
2626
export interface HandleMouseHoverParams
2727
extends Pick<
2828
EventListenerHandlerParams,
29-
"event" | "overlayWrapper" | "visualBuilderContainer"
29+
"event" | "overlayWrapper" | "visualBuilderContainer" | "focusedToolbar" | "resizeObserver"
3030
> {
3131
customCursor: HTMLDivElement | null;
3232
}
@@ -200,15 +200,6 @@ function isFieldPathDropdown(target: HTMLElement): boolean {
200200
return target.classList.contains("visual-builder__focused-toolbar__field-label-wrapper") || target.classList.contains("visual-builder__focused-toolbar__field-label-wrapper__current-field");
201201
}
202202

203-
export function syncReferenceMap() {
204-
const referenceParentMap = VisualBuilder.VisualBuilderGlobalState.value.referenceParentMap;
205-
// Only sync on first hover
206-
if(!referenceParentMap) {
207-
return;
208-
}
209-
visualBuilderPostMessage?.send(VisualBuilderPostMessageEvents.SYNC_REFERENCE_MAP);
210-
}
211-
212203
const throttledMouseHover = throttle(async (params: HandleMouseHoverParams) => {
213204
const eventDetails = getCsDataOfElement(params.event);
214205
const eventTarget = params.event.target as HTMLElement | null;
@@ -233,6 +224,16 @@ const throttledMouseHover = throttle(async (params: HandleMouseHoverParams) => {
233224
isFieldPathDropdown(eventTarget)
234225
) {
235226
showOutline();
227+
showHoverToolbar({
228+
event: params.event,
229+
overlayWrapper: params.overlayWrapper,
230+
visualBuilderContainer: params.visualBuilderContainer,
231+
previousSelectedEditableDOM:
232+
VisualBuilder.VisualBuilderGlobalState.value
233+
.previousSelectedEditableDOM,
234+
focusedToolbar: params.focusedToolbar,
235+
resizeObserver: params.resizeObserver,
236+
});
236237
}
237238
if (!config?.collab.enable) {
238239
resetCustomCursor(params.customCursor);
@@ -370,6 +371,16 @@ const throttledMouseHover = throttle(async (params: HandleMouseHoverParams) => {
370371
fieldPath,
371372
fieldMetadata,
372373
});
374+
showHoverToolbar({
375+
event: params.event,
376+
overlayWrapper: params.overlayWrapper,
377+
visualBuilderContainer: params.visualBuilderContainer,
378+
previousSelectedEditableDOM:
379+
VisualBuilder.VisualBuilderGlobalState.value
380+
.previousSelectedEditableDOM,
381+
focusedToolbar: params.focusedToolbar,
382+
resizeObserver: params.resizeObserver,
383+
});
373384
}
374385

375386
if (

src/visualBuilder/utils/types/postMessage.types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ export enum VisualBuilderPostMessageEvents {
4444
SEND_VARIANT_AND_LOCALE = "send-variant-and-locale",
4545
GET_CONTENT_TYPE_NAME = "get-content-type-name",
4646
REFERENCE_MAP = "get-reference-map",
47-
SYNC_REFERENCE_MAP = "sync-reference-map",
4847
COLLAB_ENABLE = "collab-enable",
4948
COLLAB_DATA_UPDATE = "collab-data-update",
5049
COLLAB_DISABLE = "collab-disable",

0 commit comments

Comments
 (0)