-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathuseRecalculateVariantDataCSLPValues.ts
More file actions
178 lines (167 loc) · 6.97 KB
/
useRecalculateVariantDataCSLPValues.ts
File metadata and controls
178 lines (167 loc) · 6.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
import { VisualBuilder } from "..";
import livePreviewPostMessage from "../../livePreview/eventManager/livePreviewEventManager";
import { LIVE_PREVIEW_POST_MESSAGE_EVENTS } from "../../livePreview/eventManager/livePreviewEventManager.constant";
import { DATA_CSLP_ATTR_SELECTOR } from "../utils/constants";
import { visualBuilderStyles } from "../visualBuilder.style";
import { isValidCslp } from "../../cslp/cslpdata";
import { setHighlightVariantFields } from "./useVariantsPostMessageEvent";
const VARIANT_UPDATE_DELAY_MS: Readonly<number> = 8000;
type OnAudienceModeVariantPatchUpdate = {
highlightVariantFields: boolean;
expectedCSLPValues: Record<"variant" | "base", string>;
};
/**
* Registers a post message event listener for updating the variant / base classes in the live preview for audience mode.
*/
export function useRecalculateVariantDataCSLPValues(): void {
livePreviewPostMessage?.on<OnAudienceModeVariantPatchUpdate>(
LIVE_PREVIEW_POST_MESSAGE_EVENTS.VARIANT_PATCH,
(event) => {
if (VisualBuilder.VisualBuilderGlobalState.value.audienceMode) {
setHighlightVariantFields(event.data.highlightVariantFields);
updateVariantClasses();
}
}
);
}
export function updateVariantClasses(): void {
const highlightVariantFields = VisualBuilder.VisualBuilderGlobalState.value.highlightVariantFields;
const variant = VisualBuilder.VisualBuilderGlobalState.value.variant;
const observers: MutationObserver[] = [];
// Helper function to update element classes
const updateElementClasses = (
element: HTMLElement,
dataCslp: string,
observer?: MutationObserver
) => {
if (!isValidCslp(dataCslp)) return;
if (
dataCslp.startsWith("v2:") &&
!element.classList.contains("visual-builder__variant-field")
) {
if (element.classList.contains("visual-builder__base-field")) {
element.classList.remove("visual-builder__base-field");
}
const variantFieldClasses = ["visual-builder__variant-field"];
if (highlightVariantFields) {
variantFieldClasses.push(visualBuilderStyles()["visual-builder__variant-field-outline"]);
}
element.classList.add(...variantFieldClasses);
} else if (
!dataCslp.startsWith("v2:") &&
element.classList.contains("visual-builder__variant-field")
) {
element.classList.remove(
visualBuilderStyles()["visual-builder__variant-field-outline"],
"visual-builder__variant-field"
);
element.classList.add("visual-builder__base-field");
} else if (
dataCslp.startsWith("v2:") &&
variant &&
!dataCslp.includes(variant) &&
element.classList.contains("visual-builder__variant-field")
) {
element.classList.remove(
visualBuilderStyles()["visual-builder__variant-field-outline"],
"visual-builder__variant-field"
);
element.classList.add("visual-builder__disabled-variant-field");
}
if (!observer) return;
// Disconnect this observer after processing
observer.disconnect();
const index = observers.indexOf(observer);
if (index > -1) {
observers.splice(index, 1);
}
};
const addElementClasses = (element: HTMLElement) => {
const dataCslp = element.getAttribute(DATA_CSLP_ATTR_SELECTOR);
if (!isValidCslp(dataCslp)) {
//recursive call for child nodes
element.childNodes.forEach((child) => {
if (child instanceof HTMLElement) {
addElementClasses(child);
}
});
return;
}
//if element might have been updated by another observer
if (
dataCslp.startsWith("v2:") &&
element.classList.contains("visual-builder__variant-field")
) {
return;
}
// if element has not given variant/base class
if (
dataCslp.startsWith("v2:") &&
!element.classList.contains("visual-builder__variant-field")
) {
if (element.classList.contains("visual-builder__base-field")) {
element.classList.remove("visual-builder__base-field");
}
const variantFieldClasses = ["visual-builder__variant-field"];
if (highlightVariantFields) {
variantFieldClasses.push(visualBuilderStyles()["visual-builder__variant-field-outline"]);
}
element.classList.add(...variantFieldClasses);
} else if (!dataCslp.startsWith("v2:")) {
if (element.classList.contains("visual-builder__variant-field")) {
element.classList.remove(
visualBuilderStyles()["visual-builder__variant-field-outline"],
"visual-builder__variant-field"
);
}
element.classList.add("visual-builder__base-field");
}
//recursive call for child nodes
element.childNodes.forEach((child) => {
if (child instanceof HTMLElement) {
addElementClasses(child);
}
});
};
// Create a separate observer for each element
const elementsWithCslp = document.querySelectorAll(
`[${DATA_CSLP_ATTR_SELECTOR}]`
);
elementsWithCslp.forEach((elementNode) => {
const element = elementNode as HTMLElement;
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (
(mutation.type === "attributes" &&
mutation.attributeName === DATA_CSLP_ATTR_SELECTOR) ||
mutation.type === "childList"
) {
if (mutation.addedNodes.length > 0) {
mutation.addedNodes.forEach((node) => {
if (node instanceof HTMLElement) {
addElementClasses(node);
}
});
}
const dataCslp = element.getAttribute(
DATA_CSLP_ATTR_SELECTOR
);
updateElementClasses(element, dataCslp || "", observer);
}
});
});
observers.push(observer);
// TODO: Check if we could add attributeFilter to the observer to only observe the attribute changes for the data-cslp attribute.
observer.observe(element, {
attributes: true,
childList: true, // Observe direct children
subtree: true,
});
});
setTimeout(() => {
if (observers.length > 0) {
observers.forEach((observer) => observer.disconnect());
observers.length = 0;
}
}, VARIANT_UPDATE_DELAY_MS);
}