PluginProbe
Elementor Website Builder – more than just a page builder / 4.3.1
Elementor Website Builder – more than just a page builder v4.3.1
4.3.1 4.3.0 4.3.0-beta3 4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 All 454 releases
elementor / assets / js / packages / editor-interactions / editor-interactions.js

editor-interactions.js in Elementor Website Builder – more than just a page builder 4.3.1, at assets/js/packages/editor-interactions/editor-interactions.js

2,081 lines 81.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function(react, _elementor_icons, _elementor_ui, _wordpress_i18n, _elementor_session, _elementor_editor_elements, _elementor_editor_v1_adapters, _elementor_editor_props, _elementor_editor_controls, _elementor_events, _elementor_editor_responsive, _elementor_editor_mcp, _elementor_editor_ui, _elementor_utils, _elementor_schema) {
2
3 //#region \0rolldown/runtime.js
4 var __create = Object.create;
5 var __defProp = Object.defineProperty;
6 var __name = (target, value) => __defProp(target, "name", {
7 value,
8 configurable: true
9 });
10 var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
11 var __getOwnPropNames = Object.getOwnPropertyNames;
12 var __getProtoOf = Object.getPrototypeOf;
13 var __hasOwnProp = Object.prototype.hasOwnProperty;
14 var __exportAll = (all, no_symbols) => {
15 let target = {};
16 for (var name in all) {
17 __defProp(target, name, {
18 get: all[name],
19 enumerable: true
20 });
21 }
22 if (!no_symbols) {
23 __defProp(target, Symbol.toStringTag, { value: "Module" });
24 }
25 return target;
26 };
27 var __copyProps = (to, from, except, desc) => {
28 if (from && typeof from === "object" || typeof from === "function") {
29 for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
30 key = keys[i];
31 if (!__hasOwnProp.call(to, key) && key !== except) {
32 __defProp(to, key, {
33 get: ((k) => from[k]).bind(null, key),
34 enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
35 });
36 }
37 }
38 }
39 return to;
40 };
41 var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
42 value: mod,
43 enumerable: true
44 }) : target, mod));
45
46 //#endregion
47 react = __toESM(react);
48
49 //#region packages/packages/core/editor-interactions/src/components/empty-state.tsx
50 var EmptyState = ({ onCreateInteraction }) => {
51 return /* @__PURE__ */ react.createElement(_elementor_ui.Stack, {
52 alignItems: "center",
53 justifyContent: "center",
54 height: "100%",
55 color: "text.secondary",
56 sx: {
57 p: 2.5,
58 pt: 8,
59 pb: 5.5
60 },
61 gap: 1.5
62 }, /* @__PURE__ */ react.createElement(_elementor_icons.SwipeIcon, { fontSize: "large" }), /* @__PURE__ */ react.createElement(_elementor_ui.Typography, {
63 align: "center",
64 variant: "subtitle2"
65 }, (0, _wordpress_i18n.__)("Animate elements with Interactions", "elementor")), /* @__PURE__ */ react.createElement(_elementor_ui.Typography, {
66 align: "center",
67 variant: "caption",
68 maxWidth: "170px"
69 }, (0, _wordpress_i18n.__)("Add entrance animations and effects triggered by user interactions such as page load or scroll.", "elementor")), /* @__PURE__ */ react.createElement(_elementor_ui.Button, {
70 variant: "outlined",
71 color: "secondary",
72 size: "small",
73 sx: { mt: 1 },
74 onClick: onCreateInteraction
75 }, (0, _wordpress_i18n.__)("Create an interaction", "elementor")));
76 };
77
78 //#endregion
79 //#region packages/packages/core/editor-interactions/src/interactions-controls-registry.ts
80 var controlsRegistry = /* @__PURE__ */ new Map();
81 function registerInteractionsControl({ type, component, options }) {
82 controlsRegistry.set(type, {
83 type,
84 component,
85 options
86 });
87 }
88 function getInteractionsControl(type) {
89 return controlsRegistry.get(type);
90 }
91 function getInteractionsControlOptions(type) {
92 return controlsRegistry.get(type)?.options ?? [];
93 }
94
95 //#endregion
96 //#region packages/packages/core/editor-interactions/src/configs/time-constants.ts
97 var TIME_UNITS = ["s", "ms"];
98
99 //#endregion
100 //#region packages/packages/core/editor-interactions/src/utils/size-transform-utils.ts
101 var SIZE_REGEX = /^(?:(-?\d*\.?\d+)([a-z%]+)|([a-z%]+))$/i;
102 var parseSizeValue = (value, allowedUnits, defaultValue, defaultUnit) => {
103 if (typeof value === "number") return {
104 size: value,
105 unit: defaultUnit
106 };
107 const sizeValue = tryParse(value, allowedUnits, defaultUnit);
108 if (sizeValue) return sizeValue;
109 if (defaultValue) {
110 const fallbackSize = tryParse(defaultValue, allowedUnits, defaultUnit);
111 if (fallbackSize) return fallbackSize;
112 }
113 return createSizeValue(null, defaultUnit);
114 };
115 var tryParse = (value, allowedUnits, defaultUnit) => {
116 if (typeof value === "number") return createSizeValue(value, defaultUnit);
117 const match = value && value.match(SIZE_REGEX);
118 if (!match) {
119 if (value) return {
120 size: Number(value),
121 unit: defaultUnit
122 };
123 return null;
124 }
125 const size = match[1] ? parseFloat(match[1]) : null;
126 const unit = match[2] || match[3];
127 if (!allowedUnits.includes(unit)) return null;
128 return createSizeValue(size, unit);
129 };
130 var formatSizeValue = ({ size, unit }) => {
131 return `${size ?? ""}${unit}`;
132 };
133 var createSizeValue = (size, unit) => {
134 return {
135 size,
136 unit
137 };
138 };
139
140 //#endregion
141 //#region packages/packages/core/editor-interactions/src/utils/custom-effect-to-prop-value.ts
142 var CUSTOM_EFFECT_TYPE = "custom-effect";
143 var KEYFRAMES_TYPE = "keyframes";
144 var KEYFRAME_STOP_TYPE = "keyframe-stop";
145 var KEYFRAME_STOP_SETTINGS_TYPE = "keyframe-stop-settings";
146 var SIZE_TYPE = "size";
147 var NUMBER_TYPE = "number";
148 var TRANSFORM_SCALE_TYPE = "transform-scale";
149 var TRANSFORM_ROTATE_TYPE = "transform-rotate";
150 var TRANSFORM_MOVE_TYPE = "transform-move";
151 var TRANSFORM_SKEW_TYPE = "transform-skew";
152 var UNIT_PERCENT = "%";
153 var UNIT_DEG = "deg";
154 var UNIT_PX = "px";
155 var isPlainCustomEffect = (v) => typeof v === "object" && v !== null && "keyframes" in v && Array.isArray(v.keyframes) && !("$$type" in v);
156 var toSizePropValue = (size, unit = UNIT_PERCENT) => ({
157 $$type: SIZE_TYPE,
158 value: {
159 size,
160 unit
161 }
162 });
163 var toNumberPropValue = (n) => ({
164 $$type: NUMBER_TYPE,
165 value: n
166 });
167 var toDimensionalNumberPropValue = (type, plain, defaults) => ({
168 $$type: type,
169 value: {
170 x: toNumberPropValue(plain.x ?? defaults.x),
171 y: toNumberPropValue(plain.y ?? defaults.y),
172 z: toNumberPropValue(plain.z ?? defaults.z)
173 }
174 });
175 var toDimensionalSizePropValue = (type, plain, defaults, unit) => ({
176 $$type: type,
177 value: {
178 x: toSizePropValue(plain.x ?? defaults.x, unit),
179 y: toSizePropValue(plain.y ?? defaults.y, unit),
180 z: toSizePropValue(plain.z ?? defaults.z, unit)
181 }
182 });
183 var toSkewPropValue = (plain) => ({
184 $$type: TRANSFORM_SKEW_TYPE,
185 value: {
186 x: toSizePropValue(plain.x ?? 0, UNIT_DEG),
187 y: toSizePropValue(plain.y ?? 0, UNIT_DEG)
188 }
189 });
190 var toKeyframeStopSettingsPropValue = (plain) => {
191 const value = {};
192 if (plain.opacity !== void 0) {
193 const percent = plain.opacity <= 1 ? Math.round(plain.opacity * 100) : plain.opacity;
194 value.opacity = toSizePropValue(percent);
195 }
196 if (plain.scale !== void 0) value.scale = toDimensionalNumberPropValue(TRANSFORM_SCALE_TYPE, plain.scale, {
197 x: 1,
198 y: 1,
199 z: 1
200 });
201 if (plain.rotate !== void 0) value.rotate = toDimensionalSizePropValue(TRANSFORM_ROTATE_TYPE, plain.rotate, {
202 x: 0,
203 y: 0,
204 z: 0
205 }, UNIT_DEG);
206 if (plain.move !== void 0) value.move = toDimensionalSizePropValue(TRANSFORM_MOVE_TYPE, plain.move, {
207 x: 0,
208 y: 0,
209 z: 0
210 }, UNIT_PX);
211 if (plain.skew !== void 0) value.skew = toSkewPropValue(plain.skew);
212 return {
213 $$type: KEYFRAME_STOP_SETTINGS_TYPE,
214 value
215 };
216 };
217 var isPlainKeyframe = (v) => typeof v === "object" && v !== null && "stop" in v && "value" in v && !("$$type" in v);
218 var toKeyframeStopPropValue = (item) => {
219 if (!isPlainKeyframe(item)) return item;
220 return {
221 $$type: KEYFRAME_STOP_TYPE,
222 value: {
223 stop: toSizePropValue(item.stop),
224 settings: toKeyframeStopSettingsPropValue(item.value)
225 }
226 };
227 };
228 var toKeyframesPropValue = (keyframes) => ({
229 $$type: KEYFRAMES_TYPE,
230 value: keyframes.map(toKeyframeStopPropValue)
231 });
232 var plainCustomEffectToPropValue = (plain) => ({
233 $$type: CUSTOM_EFFECT_TYPE,
234 value: { keyframes: toKeyframesPropValue(plain.keyframes) }
235 });
236 var toCustomEffectPropValue = (customEffects) => {
237 if (customEffects === void 0) return;
238 if (isPlainCustomEffect(customEffects)) return plainCustomEffectToPropValue(customEffects);
239 return customEffects;
240 };
241
242 //#endregion
243 //#region packages/packages/core/editor-interactions/src/utils/get-interactions-config.ts
244 function getInteractionsConfig() {
245 return window.ElementorInteractionsConfig ?? {};
246 }
247
248 //#endregion
249 //#region packages/packages/core/editor-interactions/src/utils/temp-id-utils.ts
250 var TEMP_ID_PREFIX = "temp-";
251 var TEMP_ID_REGEX = /^temp-[a-z0-9]+$/i;
252 function generateTempInteractionId() {
253 return `${TEMP_ID_PREFIX}${Math.random().toString(36).substring(2, 11)}`;
254 }
255 function isTempId(id) {
256 return !!id && TEMP_ID_REGEX.test(id);
257 }
258
259 //#endregion
260 //#region packages/packages/core/editor-interactions/src/utils/prop-value-utils.ts
261 var createString = (value) => ({
262 $$type: "string",
263 value
264 });
265 var createNumber = (value) => ({
266 $$type: "number",
267 value
268 });
269 var createTimingConfig = (duration, delay) => ({
270 $$type: "timing-config",
271 value: {
272 duration: _elementor_editor_props.sizePropTypeUtil.create(parseSizeValue(duration, TIME_UNITS, void 0, "ms")),
273 delay: _elementor_editor_props.sizePropTypeUtil.create(parseSizeValue(delay, TIME_UNITS, void 0, "ms"))
274 }
275 });
276 var createBoolean = (value) => ({
277 $$type: "boolean",
278 value
279 });
280 var createConfig = ({ replay, easing = "easeIn", relativeTo = "viewport", repeat = "", times = 1, start = 85, end = 15 }) => ({
281 $$type: "config",
282 value: {
283 replay: createBoolean(replay),
284 easing: createString(easing),
285 relativeTo: createString(relativeTo),
286 repeat: createString(repeat),
287 times: createNumber(times),
288 start: createSize(start, "%"),
289 end: createSize(end, "%")
290 }
291 });
292 var createSize = (value, defaultUnit, defaultValue) => {
293 if (!value) return;
294 return _elementor_editor_props.sizePropTypeUtil.create(parseSizeValue(value, ["%"], defaultValue, defaultUnit));
295 };
296 var extractBoolean = (prop, fallback = false) => {
297 return prop?.value ?? fallback;
298 };
299 var createExcludedBreakpoints = (breakpoints) => ({
300 $$type: "excluded-breakpoints",
301 value: breakpoints.map(createString)
302 });
303 var createInteractionBreakpoints = (excluded) => ({
304 $$type: "interaction-breakpoints",
305 value: { excluded: createExcludedBreakpoints(excluded) }
306 });
307 var extractExcludedBreakpoints = (breakpoints) => {
308 return breakpoints?.value.excluded.value.map((bp) => bp.value) ?? [];
309 };
310 var createAnimationPreset = ({ effect, type, direction, duration, delay, replay = false, easing = "easeIn", relativeTo, repeat, times, start, end, customEffects }) => {
311 const customEffectProp = toCustomEffectPropValue(customEffects);
312 return {
313 $$type: "animation-preset-props",
314 value: {
315 effect: createString(effect),
316 ...customEffectProp !== void 0 && { custom_effect: customEffectProp },
317 type: createString(type),
318 direction: createString(direction ?? ""),
319 timing_config: createTimingConfig(duration, delay),
320 config: createConfig({
321 replay,
322 easing,
323 relativeTo,
324 repeat,
325 times,
326 start,
327 end
328 })
329 }
330 };
331 };
332 var createInteractionItem = ({ trigger, effect, type, direction, duration, delay, interactionId, replay = false, easing = "easeIn", relativeTo, repeat, times, start, end, excludedBreakpoints, customEffects }) => ({
333 $$type: "interaction-item",
334 value: {
335 ...interactionId && { interaction_id: createString(interactionId) },
336 trigger: createString(trigger ?? ""),
337 animation: createAnimationPreset({
338 effect: effect ?? "",
339 type: type ?? "",
340 direction,
341 duration: duration ?? 0,
342 delay: delay ?? 0,
343 replay,
344 easing,
345 relativeTo,
346 repeat,
347 times,
348 start,
349 end,
350 customEffects
351 }),
352 ...excludedBreakpoints && excludedBreakpoints.length > 0 && { breakpoints: createInteractionBreakpoints(excludedBreakpoints) }
353 }
354 });
355 var createDefaultInteractionItem = () => {
356 const { constants } = getInteractionsConfig();
357 return createInteractionItem({
358 trigger: "load",
359 effect: "fade",
360 type: "in",
361 duration: constants.defaultDuration,
362 delay: constants.defaultDelay,
363 replay: false,
364 easing: constants.defaultEasing,
365 interactionId: generateTempInteractionId()
366 });
367 };
368 var createDefaultInteractions = () => ({
369 version: 1,
370 items: [createDefaultInteractionItem()]
371 });
372 var extractString = (prop, fallback = "") => {
373 return prop?.value ?? fallback;
374 };
375 var extractSize = (prop, defaultValue) => {
376 if (!prop?.value) return defaultValue;
377 return formatSizeValue(prop.value);
378 };
379 var TRIGGER_LABELS$1 = {
380 load: "On page load",
381 scrollIn: "Scroll into view",
382 scrollOut: "Scroll out of view",
383 scrollOn: "While scrolling"
384 };
385 var capitalize$1 = /* @__PURE__ */ __name((str) => {
386 return str.charAt(0).toUpperCase() + str.slice(1);
387 }, "capitalize");
388 var buildDisplayLabel = (item) => {
389 const trigger = extractString(item.trigger);
390 const effect = extractString(item.animation.value.effect);
391 const type = extractString(item.animation.value.type);
392 return `${TRIGGER_LABELS$1[trigger] || capitalize$1(trigger)}: ${capitalize$1(effect)} ${"custom" === effect ? "" : capitalize$1(type)}`;
393 };
394
395 //#endregion
396 //#region packages/packages/core/editor-interactions/src/utils/is-supported-interaction-item.ts
397 function isSupportedInteractionItem(interaction) {
398 const value = interaction.value;
399 if (true === extractBoolean(value.animation.value.config?.value.replay)) return hasSupport("replay", "yes");
400 const trigger = extractString(value.trigger);
401 const easing = extractString(value.animation.value.config?.value.easing);
402 const effect = extractString(value.animation.value.effect);
403 return [
404 ["trigger", trigger],
405 ["easing", easing],
406 ["effect", effect]
407 ].every(([controlType, controlValue]) => {
408 if (controlValue === "" || controlValue === null) return true;
409 return hasSupport(controlType, controlValue);
410 });
411 }
412 function hasSupport(controlType, controlValue) {
413 const supportedOptions = getInteractionsControlOptions(controlType);
414 if (1 > supportedOptions.length) return true;
415 return supportedOptions.includes(controlValue);
416 }
417
418 //#endregion
419 //#region packages/packages/core/editor-interactions/src/utils/filter-interactions.ts
420 var filterInteractions = (interactions) => {
421 return interactions.filter((interaction) => {
422 return isSupportedInteractionItem(interaction);
423 });
424 };
425
426 //#endregion
427 //#region packages/packages/core/editor-interactions/src/hooks/use-element-interactions.ts
428 var useElementInteractions = (elementId) => {
429 const [interactions, setInteractions] = (0, react.useState)(() => {
430 const initial = (0, _elementor_editor_elements.getElementInteractions)(elementId);
431 const filteredInteractions = filterInteractions(initial?.items ?? []);
432 return {
433 version: initial?.version ?? 1,
434 items: filteredInteractions
435 };
436 });
437 (0, _elementor_editor_v1_adapters.__privateUseListenTo)((0, _elementor_editor_v1_adapters.windowEvent)("elementor/element/update_interactions"), () => {
438 const newInteractions = (0, _elementor_editor_elements.getElementInteractions)(elementId);
439 const filteredInteractions = filterInteractions(newInteractions?.items ?? []);
440 setInteractions({
441 version: newInteractions?.version ?? 1,
442 items: filteredInteractions
443 });
444 }, [elementId]);
445 return interactions;
446 };
447
448 //#endregion
449 //#region packages/packages/core/editor-interactions/src/contexts/interactions-context.tsx
450 var InteractionsContext = (0, react.createContext)(null);
451 var DEFAULT_INTERACTIONS = {
452 version: 1,
453 items: []
454 };
455 var InteractionsProvider = ({ children, elementId }) => {
456 const rawInteractions = useElementInteractions(elementId);
457 (0, react.useEffect)(() => {
458 window.dispatchEvent(new CustomEvent("elementor/element/update_interactions"));
459 }, []);
460 const interactions = rawInteractions ?? DEFAULT_INTERACTIONS;
461 const undoableSetInteractions = (0, react.useMemo)(() => (0, _elementor_editor_v1_adapters.undoable)({
462 do: ({ interactions: newInteractions }) => {
463 const previous = (0, _elementor_editor_elements.getElementInteractions)(elementId);
464 (0, _elementor_editor_elements.updateElementInteractions)({
465 elementId,
466 interactions: newInteractions
467 });
468 return previous;
469 },
470 undo: (_, previous) => {
471 (0, _elementor_editor_elements.updateElementInteractions)({
472 elementId,
473 interactions: previous?.items?.length ? previous : void 0
474 });
475 }
476 }, {
477 title: (0, _elementor_editor_elements.getElementLabel)(elementId),
478 subtitle: ({ operationType }) => operationType === "apply" ? (0, _wordpress_i18n.__)("Interaction Applied", "elementor") : (0, _wordpress_i18n.__)("Interaction Deleted", "elementor")
479 }), [elementId]);
480 const setInteractions = (value) => {
481 const normalizedValue = value && value.items?.length === 0 ? void 0 : value;
482 const prevItemCount = interactions.items?.length ?? 0;
483 const newItemCount = normalizedValue?.items?.length ?? 0;
484 if (newItemCount > prevItemCount) undoableSetInteractions({
485 interactions: normalizedValue,
486 operationType: "apply"
487 });
488 else if (newItemCount < prevItemCount) undoableSetInteractions({
489 interactions: normalizedValue,
490 operationType: "delete"
491 });
492 else (0, _elementor_editor_elements.updateElementInteractions)({
493 elementId,
494 interactions: normalizedValue
495 });
496 };
497 const playInteractions = (interactionId) => {
498 (0, _elementor_editor_elements.playElementInteractions)(elementId, interactionId);
499 };
500 const contextValue = {
501 elementId,
502 interactions,
503 setInteractions,
504 playInteractions
505 };
506 return /* @__PURE__ */ react.createElement(InteractionsContext.Provider, { value: contextValue }, children);
507 };
508 var useInteractionsContext = () => {
509 const context = (0, react.useContext)(InteractionsContext);
510 if (!context) throw new Error("useInteractionsContext must be used within InteractionsProvider");
511 return context;
512 };
513
514 //#endregion
515 //#region packages/packages/core/editor-interactions/src/contexts/popup-state-context.tsx
516 var PopupStateContext = (0, react.createContext)(void 0);
517 var PopupStateProvider = ({ children }) => {
518 const [openByDefault, setOpenByDefault] = (0, react.useState)(false);
519 const triggerDefaultOpen = (0, react.useCallback)(() => {
520 setOpenByDefault(true);
521 }, []);
522 const resetDefaultOpen = (0, react.useCallback)(() => {
523 setOpenByDefault(false);
524 }, []);
525 return /* @__PURE__ */ react.createElement(PopupStateContext.Provider, { value: {
526 openByDefault,
527 triggerDefaultOpen,
528 resetDefaultOpen
529 } }, children);
530 };
531
532 //#endregion
533 //#region packages/packages/core/editor-interactions/src/contexts/interactions-item-context.tsx
534 var InteractionItemContext = (0, react.createContext)(null);
535 function InteractionItemContextProvider({ value, children }) {
536 return /* @__PURE__ */ react.createElement(InteractionItemContext.Provider, { value }, children);
537 }
538 function useInteractionItemContext() {
539 const context = (0, react.useContext)(InteractionItemContext);
540 if (!context) throw new Error("useInteractionItemContext must be used within InteractionItemContextProvider");
541 return context;
542 }
543
544 //#endregion
545 //#region packages/packages/core/editor-interactions/src/utils/scroll-interaction-event.ts
546 var SCROLL_INTERACTION_EVENT = "elementor/interactions/scroll-change";
547 function dispatchScrollInteraction(data) {
548 window.dispatchEvent(new CustomEvent(SCROLL_INTERACTION_EVENT, { detail: data }));
549 }
550 function extractScrollOverlayParams(interaction, defaults) {
551 return {
552 trigger: extractString(interaction.trigger, defaults.trigger),
553 start: extractSize(interaction.animation.value.config?.value.start, defaults.start),
554 end: extractSize(interaction.animation.value.config?.value.end, defaults.end),
555 relativeTo: extractString(interaction.animation.value.config?.value.relativeTo, defaults.relativeTo)
556 };
557 }
558 function syncGridOverlay(trigger, start, end, relativeTo) {
559 if (trigger === "scrollOn") dispatchScrollInteraction({
560 start,
561 end,
562 relativeTo
563 });
564 else dispatchScrollInteraction(null);
565 }
566
567 //#endregion
568 //#region packages/packages/core/editor-interactions/src/utils/tracking.ts
569 var TRIGGER_LABELS = {
570 load: "On page load",
571 scrollIn: "Scroll into view",
572 scrollOut: "Scroll out of view",
573 scrollOn: "While scrolling",
574 hover: "Hover",
575 click: "Click"
576 };
577 var capitalize = (s) => s.charAt(0).toUpperCase() + s.slice(1);
578 var trackInteractionCreated = (elementId, item) => {
579 const { dispatchEvent, config } = (0, _elementor_events.getMixpanel)();
580 if (!config?.names?.interactions?.created) return;
581 const trigger = extractString(item.value.trigger);
582 const effect = extractString(item.value.animation.value.effect);
583 const type = extractString(item.value.animation.value.type);
584 dispatchEvent?.(config.names.interactions.created, {
585 window_name: config?.appTypes?.editor,
586 interaction_type: config?.triggers?.click,
587 target_name: (0, _elementor_editor_elements.getElementLabel)(elementId),
588 interaction_result: "interaction_created",
589 target_location: config?.locations?.widgetPanel,
590 location_l1: (0, _elementor_editor_elements.getElementLabel)(elementId),
591 location_l2: "interactions",
592 interaction_description: "interaction_created",
593 interaction_trigger: TRIGGER_LABELS[trigger] ?? capitalize(trigger),
594 interaction_effect: effect === "custom" ? capitalize(effect) : `${capitalize(effect)} ${capitalize(type)}`
595 });
596 };
597
598 //#endregion
599 //#region packages/packages/core/editor-interactions/src/utils/resolve-direction.ts
600 var resolveDirection = (hasDirection, newEffect, newDirection, currentDirection, currentEffect) => {
601 if (newEffect === "slide" && !newDirection) return "top";
602 if (currentEffect === "slide" && hasDirection) return newDirection || "top";
603 if (hasDirection) return newDirection;
604 return currentDirection;
605 };
606
607 //#endregion
608 //#region packages/packages/core/editor-interactions/src/components/controls/time-frame-indicator.tsx
609 function TimeFrameIndicator({ value, onChange, defaultValue }) {
610 const sizeValue = parseSizeValue(value, TIME_UNITS, defaultValue, "ms");
611 const handleChange = (0, react.useCallback)((size) => {
612 onChange(formatSizeValue(size));
613 }, [onChange]);
614 const handleBlur = (event) => {
615 if (!event.target.value) handleChange(parseSizeValue(defaultValue, TIME_UNITS, void 0, "ms"));
616 };
617 return /* @__PURE__ */ react.createElement(_elementor_editor_controls.SizeComponent, {
618 units: TIME_UNITS,
619 value: sizeValue,
620 setValue: handleChange,
621 onBlur: handleBlur,
622 InputProps: { inputProps: { min: 0 } }
623 });
624 }
625
626 //#endregion
627 //#region packages/packages/core/editor-interactions/src/components/field.tsx
628 var Field = ({ label, children }) => {
629 return /* @__PURE__ */ react.createElement(_elementor_ui.Grid, {
630 item: true,
631 xs: 12,
632 "aria-label": `${label} control`
633 }, /* @__PURE__ */ react.createElement(_elementor_editor_controls.PopoverGridContainer, null, /* @__PURE__ */ react.createElement(_elementor_ui.Grid, {
634 item: true,
635 xs: 6
636 }, /* @__PURE__ */ react.createElement(_elementor_editor_controls.ControlFormLabel, null, label)), /* @__PURE__ */ react.createElement(_elementor_ui.Grid, {
637 item: true,
638 xs: 6
639 }, children)));
640 };
641
642 //#endregion
643 //#region packages/packages/core/editor-interactions/src/components/interaction-details.tsx
644 var DEFAULT_VALUES = {
645 trigger: "load",
646 effect: "fade",
647 type: "in",
648 direction: "",
649 duration: 600,
650 delay: 0,
651 replay: false,
652 easing: "easeIn",
653 relativeTo: "viewport",
654 repeat: "",
655 times: 1,
656 start: 85,
657 end: 15
658 };
659 var TRIGGERS_WITHOUT_REPLAY = [
660 "load",
661 "scrollOn",
662 "hover",
663 "click"
664 ];
665 var controlVisibilityConfig = {
666 replay: (values) => !TRIGGERS_WITHOUT_REPLAY.includes(values.trigger),
667 custom: (values) => values.effect === "custom",
668 effectType: (values) => values.effect !== "custom",
669 direction: (values) => values.effect !== "custom",
670 relativeTo: (values) => values.trigger === "scrollOn",
671 start: (values) => values.trigger === "scrollOn",
672 end: (values) => values.trigger === "scrollOn",
673 repeat: (values) => values.trigger !== "scrollOn",
674 times: (values) => values.trigger !== "scrollOn" && values.repeat === "times",
675 duration: (values) => {
676 return !(values.trigger === "scrollOn");
677 },
678 delay: (values) => {
679 return !(values.trigger === "scrollOn");
680 }
681 };
682 function normalizeTimesValue(value, fallback) {
683 const numericValue = Number(value);
684 if (!Number.isFinite(numericValue)) return fallback;
685 return Math.max(1, Math.floor(numericValue));
686 }
687 function useControlComponent(controlName, isVisible = true) {
688 return (0, react.useMemo)(() => {
689 if (!isVisible) return null;
690 return getInteractionsControl(controlName)?.component ?? null;
691 }, [controlName, isVisible]);
692 }
693 var InteractionDetails = ({ interaction, onChange, onPlayInteraction }) => {
694 const trigger = extractString(interaction.trigger, DEFAULT_VALUES.trigger);
695 const effect = extractString(interaction.animation.value.effect, DEFAULT_VALUES.effect);
696 const customEffects = interaction.animation.value.custom_effect;
697 const type = extractString(interaction.animation.value.type, DEFAULT_VALUES.type);
698 const direction = extractString(interaction.animation.value.direction, DEFAULT_VALUES.direction);
699 const duration = extractSize(interaction.animation.value.timing_config.value.duration);
700 const delay = extractSize(interaction.animation.value.timing_config.value.delay);
701 const replay = extractBoolean(interaction.animation.value.config?.value.replay, DEFAULT_VALUES.replay);
702 const easing = extractString(interaction.animation.value.config?.value.easing, DEFAULT_VALUES.easing);
703 const relativeTo = extractString(interaction.animation.value.config?.value.relativeTo, DEFAULT_VALUES.relativeTo);
704 const configValue = interaction.animation.value.config?.value;
705 const repeat = extractString(configValue?.repeat, DEFAULT_VALUES.repeat);
706 const times = normalizeTimesValue(configValue?.times?.value, DEFAULT_VALUES.times);
707 const start = extractSize(interaction.animation.value.config?.value.start, DEFAULT_VALUES.start);
708 const end = extractSize(interaction.animation.value.config?.value.end, DEFAULT_VALUES.end);
709 const interactionValues = {
710 trigger,
711 effect,
712 type,
713 direction,
714 duration,
715 delay,
716 easing,
717 replay,
718 relativeTo,
719 repeat,
720 times,
721 start,
722 end,
723 customEffects
724 };
725 const TriggerControl = useControlComponent("trigger", true);
726 const EffectControl = useControlComponent("effect");
727 const ReplayControl = useControlComponent("replay", controlVisibilityConfig.replay(interactionValues));
728 const RelativeToControl = useControlComponent("relativeTo", controlVisibilityConfig.relativeTo(interactionValues));
729 const StartControl = useControlComponent("start", controlVisibilityConfig.start(interactionValues));
730 const EndControl = useControlComponent("end", controlVisibilityConfig.end(interactionValues));
731 const CustomEffectControl = useControlComponent("customEffects", controlVisibilityConfig.custom(interactionValues));
732 const EffectTypeControl = useControlComponent("effectType", controlVisibilityConfig.effectType(interactionValues));
733 const DirectionControl = useControlComponent("direction", controlVisibilityConfig.direction(interactionValues));
734 const RepeatControl = useControlComponent("repeat", controlVisibilityConfig.repeat(interactionValues));
735 const TimesControl = useControlComponent("times", controlVisibilityConfig.times(interactionValues));
736 const EasingControl = useControlComponent("easing");
737 const updateInteraction = (updates) => {
738 const resolvedDirectionValue = resolveDirection("direction" in updates, updates.effect, updates.direction, direction, effect);
739 const updatedInteraction = {
740 ...interaction,
741 interaction_id: interaction.interaction_id,
742 trigger: createString(updates.trigger ?? trigger),
743 animation: createAnimationPreset({
744 effect: updates.effect ?? effect,
745 type: updates.type ?? type,
746 direction: resolvedDirectionValue,
747 duration: updates.duration ?? duration,
748 delay: updates.delay ?? delay,
749 replay: updates.replay ?? replay,
750 easing: updates.easing ?? easing,
751 relativeTo: updates.relativeTo ?? relativeTo,
752 repeat: updates.repeat ?? repeat,
753 times: updates.times ?? times,
754 start: updates.start ?? start,
755 end: updates.end ?? end,
756 customEffects: updates.customEffects ?? customEffects
757 })
758 };
759 onChange(updatedInteraction);
760 syncGridOverlay(updates.trigger ?? trigger, updates.start ?? start, updates.end ?? end, updates.relativeTo ?? relativeTo);
761 const interactionId = extractString(updatedInteraction.interaction_id);
762 setTimeout(() => {
763 onPlayInteraction(interactionId);
764 }, 0);
765 };
766 return /* @__PURE__ */ react.createElement(_elementor_editor_controls.PopoverContent, { p: 1.5 }, /* @__PURE__ */ react.createElement(_elementor_ui.Grid, {
767 container: true,
768 spacing: 1.5
769 }, TriggerControl && /* @__PURE__ */ react.createElement(Field, { label: (0, _wordpress_i18n.__)("Trigger", "elementor") }, /* @__PURE__ */ react.createElement(TriggerControl, {
770 value: trigger,
771 onChange: (v) => updateInteraction({ trigger: v })
772 })), ReplayControl && /* @__PURE__ */ react.createElement(Field, { label: (0, _wordpress_i18n.__)("Replay", "elementor") }, /* @__PURE__ */ react.createElement(ReplayControl, {
773 value: replay,
774 onChange: (v) => updateInteraction({ replay: v }),
775 disabled: true
776 }))), /* @__PURE__ */ react.createElement(_elementor_ui.Divider, null), /* @__PURE__ */ react.createElement(_elementor_ui.Grid, {
777 container: true,
778 spacing: 1.5
779 }, EffectControl && /* @__PURE__ */ react.createElement(Field, { label: (0, _wordpress_i18n.__)("Effect", "elementor") }, /* @__PURE__ */ react.createElement(EffectControl, {
780 value: effect,
781 onChange: (v) => updateInteraction({ effect: v })
782 })), CustomEffectControl && /* @__PURE__ */ react.createElement(Field, { label: (0, _wordpress_i18n.__)("Custom Effect", "elementor") }, /* @__PURE__ */ react.createElement(CustomEffectControl, {
783 value: customEffects,
784 onChange: (v) => updateInteraction({ customEffects: v })
785 })), EffectTypeControl && /* @__PURE__ */ react.createElement(Field, { label: (0, _wordpress_i18n.__)("Type", "elementor") }, /* @__PURE__ */ react.createElement(EffectTypeControl, {
786 value: type,
787 onChange: (v) => updateInteraction({ type: v })
788 })), DirectionControl && /* @__PURE__ */ react.createElement(Field, { label: (0, _wordpress_i18n.__)("Direction", "elementor") }, /* @__PURE__ */ react.createElement(DirectionControl, {
789 value: direction,
790 onChange: (v) => updateInteraction({ direction: v }),
791 interactionType: type
792 })), RepeatControl && /* @__PURE__ */ react.createElement(Field, { label: (0, _wordpress_i18n.__)("Repeat", "elementor") }, /* @__PURE__ */ react.createElement(RepeatControl, {
793 value: repeat,
794 onChange: (v) => updateInteraction({ repeat: v })
795 })), TimesControl && /* @__PURE__ */ react.createElement(Field, { label: (0, _wordpress_i18n.__)("Times", "elementor") }, /* @__PURE__ */ react.createElement(TimesControl, {
796 value: times,
797 onChange: (v) => updateInteraction({ times: normalizeTimesValue(v, DEFAULT_VALUES.times) })
798 })), controlVisibilityConfig.duration(interactionValues) && /* @__PURE__ */ react.createElement(Field, { label: (0, _wordpress_i18n.__)("Duration", "elementor") }, /* @__PURE__ */ react.createElement(TimeFrameIndicator, {
799 value: String(duration),
800 onChange: (v) => updateInteraction({ duration: v }),
801 defaultValue: DEFAULT_VALUES.duration
802 })), controlVisibilityConfig.delay(interactionValues) && /* @__PURE__ */ react.createElement(Field, { label: (0, _wordpress_i18n.__)("Delay", "elementor") }, /* @__PURE__ */ react.createElement(TimeFrameIndicator, {
803 value: String(delay),
804 onChange: (v) => updateInteraction({ delay: v }),
805 defaultValue: DEFAULT_VALUES.delay
806 }))), controlVisibilityConfig.relativeTo(interactionValues) && RelativeToControl && /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement(_elementor_ui.Divider, null), /* @__PURE__ */ react.createElement(_elementor_ui.Grid, {
807 container: true,
808 spacing: 1.5
809 }, StartControl && /* @__PURE__ */ react.createElement(Field, { label: (0, _wordpress_i18n.__)("Start", "elementor") }, /* @__PURE__ */ react.createElement(StartControl, {
810 value: parseSizeValue(start, ["%"]).size?.toString() ?? "",
811 onChange: (v) => updateInteraction({ start: v })
812 })), EndControl && /* @__PURE__ */ react.createElement(Field, { label: (0, _wordpress_i18n.__)("End", "elementor") }, /* @__PURE__ */ react.createElement(EndControl, {
813 value: parseSizeValue(end, ["%"]).size?.toString() ?? "",
814 onChange: (v) => updateInteraction({ end: v })
815 })), /* @__PURE__ */ react.createElement(Field, { label: (0, _wordpress_i18n.__)("Relative To", "elementor") }, /* @__PURE__ */ react.createElement(RelativeToControl, {
816 value: relativeTo,
817 onChange: (v) => updateInteraction({ relativeTo: v })
818 }))), /* @__PURE__ */ react.createElement(_elementor_ui.Divider, null)), EasingControl && /* @__PURE__ */ react.createElement(_elementor_ui.Grid, {
819 container: true,
820 spacing: 1.5
821 }, /* @__PURE__ */ react.createElement(Field, { label: (0, _wordpress_i18n.__)("Easing", "elementor") }, /* @__PURE__ */ react.createElement(EasingControl, {
822 value: easing,
823 onChange: (v) => {
824 updateInteraction({ easing: v });
825 }
826 }))));
827 };
828
829 //#endregion
830 //#region packages/packages/core/editor-interactions/src/components/interaction-settings.tsx
831 var SIZE = "tiny";
832 var InteractionSettings = ({ interaction, onChange }) => {
833 const breakpoints = (0, _elementor_editor_responsive.useBreakpoints)();
834 const availableBreakpoints = (0, react.useMemo)(() => breakpoints.map((breakpoint) => ({
835 label: breakpoint.label,
836 value: String(breakpoint.id)
837 })), [breakpoints]);
838 const [selectedBreakpoints, setSelectedBreakpoints] = (0, react.useState)(() => {
839 const excluded = extractExcludedBreakpoints(interaction.breakpoints).filter((excludedBreakpoint) => {
840 return availableBreakpoints.some(({ value }) => value === excludedBreakpoint);
841 });
842 return availableBreakpoints.filter(({ value }) => {
843 return !excluded.includes(value);
844 });
845 });
846 const handleBreakpointChange = (0, react.useCallback)((_, newValue) => {
847 setSelectedBreakpoints(newValue);
848 const selectedValues = newValue.map((option) => option.value);
849 const newExcluded = availableBreakpoints.filter((breakpoint) => !selectedValues.includes(breakpoint.value)).map((breakpoint) => breakpoint.value);
850 const updatedInteraction = {
851 ...interaction,
852 ...newExcluded.length > 0 && { breakpoints: createInteractionBreakpoints(newExcluded) }
853 };
854 if (newExcluded.length === 0) delete updatedInteraction.breakpoints;
855 onChange(updatedInteraction);
856 }, [
857 interaction,
858 availableBreakpoints,
859 onChange
860 ]);
861 return /* @__PURE__ */ react.createElement(_elementor_editor_controls.PopoverContent, { p: 1.5 }, /* @__PURE__ */ react.createElement(_elementor_ui.Grid, {
862 container: true,
863 spacing: 1.5
864 }, /* @__PURE__ */ react.createElement(_elementor_ui.Grid, {
865 item: true,
866 xs: 12
867 }, /* @__PURE__ */ react.createElement(_elementor_ui.Stack, {
868 direction: "column",
869 gap: 1
870 }, /* @__PURE__ */ react.createElement(_elementor_editor_controls.ControlFormLabel, { sx: { width: "100%" } }, (0, _wordpress_i18n.__)("Trigger on", "elementor")), /* @__PURE__ */ react.createElement(_elementor_ui.Autocomplete, {
871 fullWidth: true,
872 multiple: true,
873 value: selectedBreakpoints,
874 onChange: handleBreakpointChange,
875 size: SIZE,
876 options: availableBreakpoints,
877 isOptionEqualToValue: (option, value) => option.value === value.value,
878 renderInput: (params) => /* @__PURE__ */ react.createElement(_elementor_ui.TextField, { ...params }),
879 renderTags: (values, getTagProps) => values.map((option, index) => {
880 const { key, ...chipProps } = getTagProps({ index });
881 return /* @__PURE__ */ react.createElement(_elementor_ui.Chip, {
882 key,
883 size: SIZE,
884 label: option.label,
885 ...chipProps
886 });
887 })
888 })))));
889 };
890
891 //#endregion
892 //#region packages/packages/core/editor-interactions/src/components/interactions-list-item.tsx
893 var InteractionsListItem = ({ index, value: interaction }) => {
894 const { getTabsProps, getTabProps, getTabPanelProps } = (0, _elementor_ui.useTabs)("details");
895 const context = useInteractionItemContext();
896 const handleChange = (0, react.useCallback)((newInteractionValue) => {
897 context?.onInteractionChange(index, newInteractionValue);
898 }, [context, index]);
899 const handlePlayInteraction = (0, react.useCallback)((interactionId2) => {
900 context?.onPlayInteraction(interactionId2);
901 }, [context]);
902 const interactionId = extractString(interaction.value.interaction_id);
903 return /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement(_elementor_ui.Tabs, {
904 size: "small",
905 variant: "fullWidth",
906 "aria-label": (0, _wordpress_i18n.__)("Interaction", "elementor"),
907 ...getTabsProps()
908 }, /* @__PURE__ */ react.createElement(_elementor_ui.Tab, {
909 label: (0, _wordpress_i18n.__)("Details", "elementor"),
910 ...getTabProps("details")
911 }), /* @__PURE__ */ react.createElement(_elementor_ui.Tab, {
912 label: (0, _wordpress_i18n.__)("Settings", "elementor"),
913 ...getTabProps("settings")
914 })), /* @__PURE__ */ react.createElement(_elementor_ui.Divider, null), /* @__PURE__ */ react.createElement(_elementor_ui.TabPanel, {
915 sx: { p: 0 },
916 ...getTabPanelProps("details")
917 }, /* @__PURE__ */ react.createElement(InteractionDetails, {
918 key: interactionId,
919 interaction: interaction.value,
920 onChange: handleChange,
921 onPlayInteraction: handlePlayInteraction
922 })), /* @__PURE__ */ react.createElement(_elementor_ui.TabPanel, {
923 sx: { p: 0 },
924 ...getTabPanelProps("settings")
925 }, /* @__PURE__ */ react.createElement(InteractionSettings, {
926 key: interactionId,
927 interaction: interaction.value,
928 onChange: handleChange
929 })));
930 };
931
932 //#endregion
933 //#region packages/packages/core/editor-interactions/src/components/interactions-list.tsx
934 var MAX_NUMBER_OF_INTERACTIONS = 5;
935 function InteractionsList(props) {
936 const { interactions, onSelectInteractions, onPlayInteraction, triggerCreateOnShowEmpty } = props;
937 const { elementId } = useInteractionsContext();
938 const hasInitializedRef = (0, react.useRef)(false);
939 const newlyCreatedIdsRef = (0, react.useRef)(/* @__PURE__ */ new Set());
940 const handleUpdateInteractions = (0, react.useCallback)((newInteractions) => {
941 onSelectInteractions(newInteractions);
942 }, [onSelectInteractions]);
943 (0, react.useEffect)(() => {
944 if (triggerCreateOnShowEmpty && !hasInitializedRef.current && (!interactions.items || interactions.items?.length === 0)) {
945 hasInitializedRef.current = true;
946 const newItem = createDefaultInteractionItem();
947 newlyCreatedIdsRef.current.add(extractString(newItem.value.interaction_id));
948 handleUpdateInteractions({
949 version: 1,
950 items: [newItem]
951 });
952 }
953 }, [
954 triggerCreateOnShowEmpty,
955 interactions.items,
956 handleUpdateInteractions
957 ]);
958 const isMaxNumberOfInteractionsReached = (0, react.useMemo)(() => {
959 return interactions.items?.length >= 5;
960 }, [interactions.items?.length]);
961 const infotipContent = isMaxNumberOfInteractionsReached ? /* @__PURE__ */ react.createElement(_elementor_ui.Alert, {
962 color: "secondary",
963 icon: /* @__PURE__ */ react.createElement(_elementor_icons.InfoCircleFilledIcon, null),
964 size: "small"
965 }, /* @__PURE__ */ react.createElement(_elementor_ui.AlertTitle, null, (0, _wordpress_i18n.__)("Interactions", "elementor")), /* @__PURE__ */ react.createElement(_elementor_ui.Box, { component: "span" }, (0, _wordpress_i18n.__)("You've reached the limit of 5 interactions for this element. Please remove an interaction before creating a new one.", "elementor"))) : void 0;
966 const handleRepeaterChange = (0, react.useCallback)((newItems, _, meta) => {
967 handleUpdateInteractions({
968 ...interactions,
969 items: newItems
970 });
971 if (meta?.action?.type === "add") {
972 const addedItem = meta.action.payload[0]?.item;
973 if (addedItem) newlyCreatedIdsRef.current.add(extractString(addedItem.value.interaction_id));
974 }
975 }, [interactions, handleUpdateInteractions]);
976 const handleInteractionChange = (0, react.useCallback)((index, newInteractionValue) => {
977 const newItems = structuredClone(interactions.items);
978 newItems[index] = {
979 $$type: "interaction-item",
980 value: newInteractionValue
981 };
982 handleUpdateInteractions({
983 ...interactions,
984 items: newItems
985 });
986 }, [interactions, handleUpdateInteractions]);
987 const contextValue = (0, react.useMemo)(() => ({
988 onInteractionChange: handleInteractionChange,
989 onPlayInteraction
990 }), [handleInteractionChange, onPlayInteraction]);
991 return /* @__PURE__ */ react.createElement(InteractionItemContextProvider, { value: contextValue }, /* @__PURE__ */ react.createElement(_elementor_editor_controls.Repeater, {
992 openOnAdd: true,
993 openItem: triggerCreateOnShowEmpty ? 0 : void 0,
994 label: (0, _wordpress_i18n.__)("Interactions", "elementor"),
995 values: interactions.items,
996 setValues: handleRepeaterChange,
997 showDuplicate: false,
998 showToggle: false,
999 isSortable: false,
1000 disableAddItemButton: isMaxNumberOfInteractionsReached,
1001 addButtonInfotipContent: infotipContent,
1002 itemSettings: {
1003 initialValues: createDefaultInteractionItem(),
1004 Label: ({ value }) => buildDisplayLabel(value.value),
1005 Icon: () => null,
1006 Content: InteractionsListItem,
1007 onPopoverOpen: (value) => {
1008 const { trigger, start, end, relativeTo } = extractScrollOverlayParams(value.value, DEFAULT_VALUES);
1009 syncGridOverlay(trigger, start, end, relativeTo);
1010 },
1011 onPopoverClose: (value) => {
1012 dispatchScrollInteraction(null);
1013 const id = extractString(value.value.interaction_id);
1014 if (newlyCreatedIdsRef.current.has(id)) {
1015 newlyCreatedIdsRef.current.delete(id);
1016 trackInteractionCreated(elementId, value);
1017 }
1018 },
1019 actions: (value) => /* @__PURE__ */ react.createElement(_elementor_ui.Tooltip, {
1020 key: "preview",
1021 placement: "top",
1022 title: (0, _wordpress_i18n.__)("Preview", "elementor")
1023 }, /* @__PURE__ */ react.createElement(_elementor_ui.IconButton, {
1024 "aria-label": (0, _wordpress_i18n.__)("Play interaction", "elementor"),
1025 size: "tiny",
1026 onClick: () => onPlayInteraction(extractString(value.value.interaction_id))
1027 }, /* @__PURE__ */ react.createElement(_elementor_icons.PlayerPlayIcon, { fontSize: "tiny" })))
1028 }
1029 }));
1030 }
1031
1032 //#endregion
1033 //#region packages/packages/core/editor-interactions/src/components/interactions-tab.tsx
1034 var InteractionsTab = ({ elementId }) => {
1035 return /* @__PURE__ */ react.createElement(PopupStateProvider, null, /* @__PURE__ */ react.createElement(InteractionsTabContent, { elementId }));
1036 };
1037 function InteractionsTabContent({ elementId }) {
1038 const existingInteractions = useElementInteractions(elementId);
1039 const firstInteractionState = (0, react.useState)(false);
1040 const hasInteractions = existingInteractions?.items?.length || firstInteractionState[0];
1041 return /* @__PURE__ */ react.createElement(_elementor_session.SessionStorageProvider, { prefix: elementId }, hasInteractions ? /* @__PURE__ */ react.createElement(InteractionsProvider, { elementId }, /* @__PURE__ */ react.createElement(InteractionsContent, { firstInteractionState })) : /* @__PURE__ */ react.createElement(EmptyState, { onCreateInteraction: () => {
1042 firstInteractionState[1](true);
1043 } }));
1044 }
1045 function InteractionsContent({ firstInteractionState }) {
1046 const { interactions, setInteractions, playInteractions } = useInteractionsContext();
1047 const applyInteraction = (0, react.useCallback)((newInteractions) => {
1048 firstInteractionState[1](false);
1049 if (!newInteractions) {
1050 setInteractions(void 0);
1051 return;
1052 }
1053 setInteractions(newInteractions);
1054 }, [setInteractions, firstInteractionState]);
1055 return /* @__PURE__ */ react.createElement(_elementor_ui.Stack, {
1056 sx: {
1057 m: 1,
1058 p: 1.5
1059 },
1060 gap: 2
1061 }, /* @__PURE__ */ react.createElement(InteractionsList, {
1062 triggerCreateOnShowEmpty: firstInteractionState[0],
1063 interactions,
1064 onSelectInteractions: applyInteraction,
1065 onPlayInteraction: playInteractions
1066 }));
1067 }
1068
1069 //#endregion
1070 //#region packages/packages/core/editor-interactions/src/utils/create-interactions-repository.ts
1071 var createInteractionsRepository = () => {
1072 const providers = [];
1073 const getProviders = () => {
1074 return providers.slice(0).sort((a, b) => a.priority > b.priority ? -1 : 1);
1075 };
1076 const register = (provider) => {
1077 providers.push(provider);
1078 };
1079 const all = () => {
1080 return getProviders().flatMap((provider) => provider.actions.all());
1081 };
1082 const subscribe = (cb) => {
1083 const unsubscribes = providers.map((provider) => provider.subscribe(cb));
1084 return () => {
1085 unsubscribes.forEach((unsubscribe) => unsubscribe());
1086 };
1087 };
1088 const getProviderByKey = (key) => {
1089 return providers.find((provider) => {
1090 try {
1091 return provider.getKey() === key;
1092 } catch {
1093 return false;
1094 }
1095 });
1096 };
1097 return {
1098 all,
1099 register,
1100 subscribe,
1101 getProviders,
1102 getProviderByKey
1103 };
1104 };
1105
1106 //#endregion
1107 //#region packages/packages/core/editor-interactions/src/interactions-repository.ts
1108 var interactionsRepository = createInteractionsRepository();
1109
1110 //#endregion
1111 //#region packages/packages/core/editor-interactions/src/utils/create-interactions-provider.ts
1112 var DEFAULT_PRIORITY = 10;
1113 function createInteractionsProvider({ key, priority = DEFAULT_PRIORITY, subscribe = () => () => {}, actions }) {
1114 return {
1115 getKey: typeof key === "string" ? () => key : key,
1116 priority,
1117 subscribe,
1118 actions: { all: actions.all }
1119 };
1120 }
1121
1122 //#endregion
1123 //#region packages/packages/core/editor-interactions/src/providers/document-elements-interactions-provider.ts
1124 var ELEMENTS_INTERACTIONS_PROVIDER_KEY_PREFIX = "document-elements-interactions-";
1125 var documentElementsInteractionsProvider = createInteractionsProvider({
1126 key: () => {
1127 const documentId = (0, _elementor_editor_elements.getCurrentDocumentId)();
1128 if (!documentId) return `${ELEMENTS_INTERACTIONS_PROVIDER_KEY_PREFIX}pending`;
1129 return `${ELEMENTS_INTERACTIONS_PROVIDER_KEY_PREFIX}${documentId}`;
1130 },
1131 priority: 50,
1132 subscribe: (cb) => {
1133 return (0, _elementor_editor_v1_adapters.__privateListenTo)([(0, _elementor_editor_v1_adapters.windowEvent)("elementor/element/update_interactions")], () => cb());
1134 },
1135 actions: { all: () => {
1136 return (0, _elementor_editor_elements.getElements)().filter((element) => {
1137 const interactions = (0, _elementor_editor_elements.getElementInteractions)(element.id);
1138 if (!interactions) return false;
1139 return interactions?.items?.length > 0;
1140 }).map((element) => {
1141 const interactions = (0, _elementor_editor_elements.getElementInteractions)(element.id);
1142 return {
1143 elementId: element.id,
1144 dataId: element.id,
1145 interactions: interactions || {
1146 version: 1,
1147 items: []
1148 }
1149 };
1150 });
1151 } }
1152 });
1153
1154 //#endregion
1155 //#region packages/packages/core/editor-interactions/src/commands/get-clipboard-elements.ts
1156 function getClipboardElements(storageKey = "clipboard") {
1157 try {
1158 return JSON.parse(localStorage.getItem("elementor") ?? "{}")[storageKey]?.elements;
1159 } catch {
1160 return;
1161 }
1162 }
1163
1164 //#endregion
1165 //#region packages/packages/core/editor-interactions/src/commands/paste-interactions.ts
1166 function isAtomicContainer(container) {
1167 const type = container?.model.get("widgetType") || container?.model.get("elType");
1168 const elementConfig = (0, _elementor_editor_elements.getWidgetsCache)()?.[type];
1169 return Boolean(elementConfig?.atomic_props_schema);
1170 }
1171 function getTitleForContainers(containers) {
1172 return containers.length > 1 ? (0, _wordpress_i18n.__)("Elements", "elementor") : (0, _elementor_editor_elements.getElementLabel)(containers[0].id);
1173 }
1174 function normalizeClipboardInteractions(raw) {
1175 if (!raw) return null;
1176 const parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
1177 const payload = {
1178 version: parsed?.version ?? 1,
1179 items: parsed?.items?.filter((item) => isSupportedInteractionItem(item)) ?? []
1180 };
1181 if (!payload.items.length) return null;
1182 return payload;
1183 }
1184 function regenerateInteractionIds(interactions) {
1185 const cloned = structuredClone(interactions);
1186 cloned.items?.forEach((item) => {
1187 if (item.$$type === "interaction-item" && item.value) item.value.interaction_id = createString(generateTempInteractionId());
1188 });
1189 return cloned;
1190 }
1191 function initPasteInteractionsCommand() {
1192 const undoablePasteInteractions = (0, _elementor_editor_v1_adapters.undoable)({
1193 do: ({ containers, newInteractions }) => {
1194 const pasted = regenerateInteractionIds(newInteractions);
1195 return containers.map((container) => {
1196 const elementId = container.id;
1197 const previous = (0, _elementor_editor_elements.getElementInteractions)(elementId);
1198 (0, _elementor_editor_elements.updateElementInteractions)({
1199 elementId,
1200 interactions: pasted
1201 });
1202 return {
1203 elementId,
1204 previous: previous ?? {
1205 version: 1,
1206 items: []
1207 }
1208 };
1209 });
1210 },
1211 undo: (_, revertData) => {
1212 revertData.forEach(({ elementId, previous }) => {
1213 (0, _elementor_editor_elements.updateElementInteractions)({
1214 elementId,
1215 interactions: previous.items?.length ? previous : void 0
1216 });
1217 });
1218 }
1219 }, {
1220 title: ({ containers }) => getTitleForContainers(containers),
1221 subtitle: (0, _wordpress_i18n.__)("Interactions Pasted", "elementor")
1222 });
1223 (0, _elementor_editor_v1_adapters.__privateListenTo)((0, _elementor_editor_v1_adapters.commandStartEvent)("document/elements/paste-interactions"), (e) => {
1224 const args = e.args;
1225 const containers = args.containers ?? (args.container ? [args.container] : []);
1226 const storageKey = args.storageKey ?? "clipboard";
1227 if (!containers.length) return;
1228 const [clipboardElement] = getClipboardElements(storageKey) ?? [];
1229 if (!clipboardElement) return;
1230 const newInteractions = normalizeClipboardInteractions(clipboardElement.interactions);
1231 if (!newInteractions) return;
1232 const validContainers = containers.filter((c) => (0, _elementor_editor_elements.getContainer)(c.id)).filter(isAtomicContainer);
1233 if (!validContainers.length) return;
1234 undoablePasteInteractions({
1235 containers: validContainers,
1236 newInteractions
1237 });
1238 });
1239 }
1240
1241 //#endregion
1242 //#region packages/packages/core/editor-interactions/src/components/controls/direction.tsx
1243 var AXIS = {
1244 top: "vertical",
1245 bottom: "vertical",
1246 left: "horizontal",
1247 right: "horizontal"
1248 };
1249 function parseValue(value) {
1250 return value.split("-").filter(Boolean);
1251 }
1252 function serializeValue(directions) {
1253 const vertical = directions.find((d) => d === "top" || d === "bottom");
1254 const horizontal = directions.find((d) => d === "left" || d === "right");
1255 if (vertical && horizontal) return `${vertical}-${horizontal}`;
1256 return directions[0] ?? "";
1257 }
1258 function toggleDirection(current, clicked) {
1259 if (current.includes(clicked)) return current.filter((d) => d !== clicked);
1260 return [...current.filter((d) => AXIS[d] !== AXIS[clicked]), clicked];
1261 }
1262 function Direction({ value, onChange, interactionType }) {
1263 const isIn = interactionType === "in";
1264 const options = (0, react.useMemo)(() => [
1265 {
1266 dir: "top",
1267 label: isIn ? (0, _wordpress_i18n.__)("From top", "elementor") : (0, _wordpress_i18n.__)("To top", "elementor"),
1268 Icon: isIn ? _elementor_icons.ArrowDownSmallIcon : _elementor_icons.ArrowUpSmallIcon
1269 },
1270 {
1271 dir: "bottom",
1272 label: isIn ? (0, _wordpress_i18n.__)("From bottom", "elementor") : (0, _wordpress_i18n.__)("To bottom", "elementor"),
1273 Icon: isIn ? _elementor_icons.ArrowUpSmallIcon : _elementor_icons.ArrowDownSmallIcon
1274 },
1275 {
1276 dir: "left",
1277 label: isIn ? (0, _wordpress_i18n.__)("From left", "elementor") : (0, _wordpress_i18n.__)("To left", "elementor"),
1278 Icon: isIn ? _elementor_icons.ArrowRightIcon : _elementor_icons.ArrowLeftIcon
1279 },
1280 {
1281 dir: "right",
1282 label: isIn ? (0, _wordpress_i18n.__)("From right", "elementor") : (0, _wordpress_i18n.__)("To right", "elementor"),
1283 Icon: isIn ? _elementor_icons.ArrowLeftIcon : _elementor_icons.ArrowRightIcon
1284 }
1285 ], [isIn]);
1286 const selectedDirections = (0, react.useMemo)(() => parseValue(value), [value]);
1287 return /* @__PURE__ */ react.createElement(_elementor_editor_controls.StyledToggleButtonGroup, {
1288 size: "tiny",
1289 justify: "end",
1290 sx: {
1291 display: "grid",
1292 gridTemplateColumns: "repeat(4, minmax(0, 25%))",
1293 width: "100%"
1294 }
1295 }, options.map(({ dir, label, Icon }) => /* @__PURE__ */ react.createElement(_elementor_ui.Tooltip, {
1296 key: dir,
1297 title: label,
1298 disableFocusListener: true,
1299 placement: "top"
1300 }, /* @__PURE__ */ react.createElement(_elementor_editor_controls.StyledToggleButton, {
1301 value: dir,
1302 selected: selectedDirections.includes(dir),
1303 "aria-label": label,
1304 size: "tiny",
1305 isPlaceholder: false,
1306 onChange: () => {
1307 onChange(serializeValue(toggleDirection(selectedDirections, dir)));
1308 }
1309 }, /* @__PURE__ */ react.createElement(Icon, { fontSize: "tiny" })))));
1310 }
1311
1312 //#endregion
1313 //#region packages/packages/core/editor-interactions/src/ui/interactions-promotion-chip.tsx
1314 var InteractionsPromotionChip = (0, react.forwardRef)(({ content, upgradeUrl, anchorRef, trackingData }, ref) => {
1315 const [isOpen, setIsOpen] = (0, react.useState)(false);
1316 (0, _elementor_editor_ui.useCanvasClickHandler)(isOpen, () => setIsOpen(false));
1317 const toggle = (0, react.useCallback)(() => {
1318 setIsOpen((prev) => {
1319 if (!prev) (0, _elementor_editor_controls.trackViewPromotion)(trackingData);
1320 return !prev;
1321 });
1322 }, [trackingData]);
1323 (0, react.useImperativeHandle)(ref, () => ({ toggle }), [toggle]);
1324 const handleToggle = (e) => {
1325 e.stopPropagation();
1326 toggle();
1327 };
1328 return /* @__PURE__ */ react.createElement(_elementor_editor_ui.PromotionPopover, {
1329 open: isOpen,
1330 title: (0, _wordpress_i18n.__)("Interactions", "elementor"),
1331 content,
1332 ctaText: (0, _wordpress_i18n.__)("Upgrade now", "elementor"),
1333 ctaUrl: upgradeUrl,
1334 anchorRef,
1335 placement: anchorRef ? "right-start" : void 0,
1336 onClose: (e) => {
1337 e.stopPropagation();
1338 setIsOpen(false);
1339 },
1340 onCtaClick: () => (0, _elementor_editor_controls.trackUpgradePromotionClick)(trackingData)
1341 }, /* @__PURE__ */ react.createElement(_elementor_ui.Box, {
1342 onMouseDown: (e) => e.stopPropagation(),
1343 onClick: handleToggle,
1344 sx: {
1345 cursor: "pointer",
1346 display: "inline-flex",
1347 mr: 1
1348 }
1349 }, /* @__PURE__ */ react.createElement(_elementor_editor_ui.PromotionChip, null)));
1350 });
1351
1352 //#endregion
1353 //#region packages/packages/core/editor-interactions/src/ui/promotion-select.tsx
1354 function PromotionSelect({ value, onChange, baseOptions, disabledOptions, promotionLabel, promotionContent, upgradeUrl, trackingData }) {
1355 const promotionRef = (0, react.useRef)(null);
1356 const anchorRef = (0, react.useRef)(null);
1357 return /* @__PURE__ */ react.createElement(_elementor_ui.Select, {
1358 value,
1359 onChange: (e) => onChange?.(e.target.value),
1360 fullWidth: true,
1361 displayEmpty: true,
1362 size: "tiny",
1363 MenuProps: { disablePortal: true }
1364 }, Object.entries(baseOptions).map(([key, label]) => /* @__PURE__ */ react.createElement(_elementor_editor_ui.MenuListItem, {
1365 key,
1366 value: key
1367 }, label)), /* @__PURE__ */ react.createElement(_elementor_ui.MenuSubheader, {
1368 ref: anchorRef,
1369 sx: {
1370 cursor: "pointer",
1371 color: "text.tertiary",
1372 fontWeight: "400",
1373 display: "flex",
1374 alignItems: "center"
1375 },
1376 onMouseDown: (e) => {
1377 e.stopPropagation();
1378 promotionRef.current?.toggle();
1379 }
1380 }, promotionLabel ?? (0, _wordpress_i18n.__)("PRO features", "elementor"), /* @__PURE__ */ react.createElement(InteractionsPromotionChip, {
1381 content: promotionContent,
1382 upgradeUrl,
1383 ref: promotionRef,
1384 anchorRef,
1385 trackingData
1386 })), Object.entries(disabledOptions).map(([key, label]) => /* @__PURE__ */ react.createElement(_elementor_editor_ui.MenuListItem, {
1387 key,
1388 value: key,
1389 disabled: true,
1390 sx: { pl: 3 }
1391 }, label)));
1392 }
1393
1394 //#endregion
1395 //#region packages/packages/core/editor-interactions/src/components/controls/easing.tsx
1396 var TRACKING_DATA$4 = {
1397 target_name: "interactions_easing",
1398 location_l2: "interactions"
1399 };
1400 var EASING_OPTIONS = {
1401 easeIn: (0, _wordpress_i18n.__)("Ease In", "elementor"),
1402 easeInOut: (0, _wordpress_i18n.__)("Ease In Out", "elementor"),
1403 easeOut: (0, _wordpress_i18n.__)("Ease Out", "elementor"),
1404 backIn: (0, _wordpress_i18n.__)("Back In", "elementor"),
1405 backInOut: (0, _wordpress_i18n.__)("Back In Out", "elementor"),
1406 backOut: (0, _wordpress_i18n.__)("Back Out", "elementor"),
1407 linear: (0, _wordpress_i18n.__)("Linear", "elementor")
1408 };
1409 var BASE_EASINGS = ["easeIn"];
1410 function Easing({}) {
1411 const baseOptions = Object.fromEntries(Object.entries(EASING_OPTIONS).filter(([key]) => BASE_EASINGS.includes(key)));
1412 const disabledOptions = Object.fromEntries(Object.entries(EASING_OPTIONS).filter(([key]) => !BASE_EASINGS.includes(key)));
1413 return /* @__PURE__ */ react.createElement(PromotionSelect, {
1414 value: DEFAULT_VALUES.easing,
1415 baseOptions,
1416 disabledOptions,
1417 promotionContent: (0, _wordpress_i18n.__)("Upgrade to control the smoothness of the interaction.", "elementor"),
1418 upgradeUrl: "https://go.elementor.com/go-pro-interactions-easing-modal/",
1419 trackingData: TRACKING_DATA$4
1420 });
1421 }
1422
1423 //#endregion
1424 //#region packages/packages/core/editor-interactions/src/components/controls/effect.tsx
1425 var TRACKING_DATA$3 = {
1426 target_name: "interactions_effect",
1427 location_l2: "interactions"
1428 };
1429 var EFFECT_OPTIONS = {
1430 fade: (0, _wordpress_i18n.__)("Fade", "elementor"),
1431 slide: (0, _wordpress_i18n.__)("Slide", "elementor"),
1432 scale: (0, _wordpress_i18n.__)("Scale", "elementor"),
1433 custom: (0, _wordpress_i18n.__)("Custom", "elementor")
1434 };
1435 var BASE_EFFECTS = [
1436 "fade",
1437 "slide",
1438 "scale"
1439 ];
1440 function Effect({ value, onChange }) {
1441 const baseOptions = Object.fromEntries(Object.entries(EFFECT_OPTIONS).filter(([key]) => BASE_EFFECTS.includes(key)));
1442 const disabledOptions = Object.fromEntries(Object.entries(EFFECT_OPTIONS).filter(([key]) => !BASE_EFFECTS.includes(key)));
1443 return /* @__PURE__ */ react.createElement(PromotionSelect, {
1444 value: value in baseOptions ? value : DEFAULT_VALUES.effect,
1445 onChange,
1446 baseOptions,
1447 disabledOptions,
1448 promotionLabel: (0, _wordpress_i18n.__)("PRO effects", "elementor"),
1449 promotionContent: (0, _wordpress_i18n.__)("Upgrade to further customize your animation with opacity, scale, move, rotate and more.", "elementor"),
1450 upgradeUrl: "https://go.elementor.com/go-pro-interactions-custom-effect-modal/",
1451 trackingData: TRACKING_DATA$3
1452 });
1453 }
1454
1455 //#endregion
1456 //#region packages/packages/core/editor-interactions/src/components/controls/effect-type.tsx
1457 function EffectType({ value, onChange }) {
1458 const options = [{
1459 value: "in",
1460 label: (0, _wordpress_i18n.__)("In", "elementor"),
1461 renderContent: () => (0, _wordpress_i18n.__)("In", "elementor"),
1462 showTooltip: true
1463 }, {
1464 value: "out",
1465 label: (0, _wordpress_i18n.__)("Out", "elementor"),
1466 renderContent: () => (0, _wordpress_i18n.__)("Out", "elementor"),
1467 showTooltip: true
1468 }];
1469 return /* @__PURE__ */ react.createElement(_elementor_editor_controls.ToggleButtonGroupUi, {
1470 items: options,
1471 exclusive: true,
1472 onChange,
1473 value
1474 });
1475 }
1476
1477 //#endregion
1478 //#region packages/packages/core/editor-interactions/src/ui/promotion-overlay-layout.tsx
1479 var OVERLAY_GRID = "1 / 1";
1480 var CHIP_OFFSET = "50%";
1481 var PromotionOverlayLayout = (0, react.forwardRef)(({ children, promotionChip }, ref) => /* @__PURE__ */ react.createElement(_elementor_ui.Box, {
1482 ref,
1483 sx: {
1484 display: "grid",
1485 alignItems: "center"
1486 }
1487 }, /* @__PURE__ */ react.createElement(_elementor_ui.Box, { sx: { gridArea: OVERLAY_GRID } }, children), /* @__PURE__ */ react.createElement(_elementor_ui.Box, { sx: {
1488 gridArea: OVERLAY_GRID,
1489 marginInlineEnd: CHIP_OFFSET,
1490 justifySelf: "end"
1491 } }, promotionChip)));
1492
1493 //#endregion
1494 //#region packages/packages/core/editor-interactions/src/components/controls/repeat.tsx
1495 var TRACKING_DATA$2 = {
1496 target_name: "interactions_repeat",
1497 location_l2: "interactions"
1498 };
1499 var REPEAT_OPTIONS = {
1500 times: (0, _wordpress_i18n.__)("times", "elementor"),
1501 loop: (0, _wordpress_i18n.__)("loop", "elementor")
1502 };
1503 var REPEAT_TOOLTIPS = {
1504 times: (0, _wordpress_i18n.__)("Enable number", "elementor"),
1505 loop: (0, _wordpress_i18n.__)("Infinite repeat", "elementor")
1506 };
1507 function Repeat() {
1508 const repeatContainerRef = (0, react.useRef)(null);
1509 const options = [{
1510 value: REPEAT_OPTIONS.times,
1511 disabled: true,
1512 label: REPEAT_TOOLTIPS.times,
1513 renderContent: ({ size }) => /* @__PURE__ */ react.createElement(_elementor_icons.Number123Icon, { fontSize: size }),
1514 showTooltip: true
1515 }, {
1516 value: REPEAT_OPTIONS.loop,
1517 disabled: true,
1518 label: REPEAT_TOOLTIPS.loop,
1519 renderContent: ({ size }) => /* @__PURE__ */ react.createElement(_elementor_icons.RepeatIcon, { fontSize: size }),
1520 showTooltip: true
1521 }];
1522 return /* @__PURE__ */ react.createElement(PromotionOverlayLayout, {
1523 ref: repeatContainerRef,
1524 promotionChip: /* @__PURE__ */ react.createElement(InteractionsPromotionChip, {
1525 content: (0, _wordpress_i18n.__)("Upgrade to control how many times the animation repeats.", "elementor"),
1526 upgradeUrl: "https://go.elementor.com/go-pro-interactions-repeat-modal/",
1527 anchorRef: repeatContainerRef,
1528 trackingData: TRACKING_DATA$2
1529 })
1530 }, /* @__PURE__ */ react.createElement(_elementor_editor_controls.ToggleButtonGroupUi, {
1531 items: options,
1532 exclusive: true,
1533 onChange: () => {},
1534 value: ""
1535 }));
1536 }
1537
1538 //#endregion
1539 //#region packages/packages/core/editor-interactions/src/components/controls/replay.tsx
1540 var TRACKING_DATA$1 = {
1541 target_name: "interactions_replay",
1542 location_l2: "interactions"
1543 };
1544 var REPLAY_OPTIONS = {
1545 no: (0, _wordpress_i18n.__)("No", "elementor"),
1546 yes: (0, _wordpress_i18n.__)("Yes", "elementor")
1547 };
1548 var BASE_REPLAY = ["no"];
1549 function Replay({ onChange }) {
1550 const replayContainerRef = (0, react.useRef)(null);
1551 const options = [{
1552 value: false,
1553 disabled: false,
1554 label: REPLAY_OPTIONS.no,
1555 renderContent: ({ size }) => /* @__PURE__ */ react.createElement(_elementor_icons.MinusIcon, { fontSize: size }),
1556 showTooltip: true
1557 }, {
1558 value: true,
1559 disabled: true,
1560 label: REPLAY_OPTIONS.yes,
1561 renderContent: ({ size }) => /* @__PURE__ */ react.createElement(_elementor_icons.CheckIcon, { fontSize: size }),
1562 showTooltip: true
1563 }];
1564 return /* @__PURE__ */ react.createElement(PromotionOverlayLayout, {
1565 ref: replayContainerRef,
1566 promotionChip: /* @__PURE__ */ react.createElement(InteractionsPromotionChip, {
1567 content: (0, _wordpress_i18n.__)("Upgrade to run the animation every time its trigger occurs.", "elementor"),
1568 upgradeUrl: "https://go.elementor.com/go-pro-interactions-replay-modal/",
1569 anchorRef: replayContainerRef,
1570 trackingData: TRACKING_DATA$1
1571 })
1572 }, /* @__PURE__ */ react.createElement(_elementor_editor_controls.ToggleButtonGroupUi, {
1573 items: options,
1574 exclusive: true,
1575 onChange,
1576 value: false
1577 }));
1578 }
1579
1580 //#endregion
1581 //#region packages/packages/core/editor-interactions/src/components/controls/trigger.tsx
1582 var TRACKING_DATA = {
1583 target_name: "interactions_trigger",
1584 location_l2: "interactions"
1585 };
1586 var TRIGGER_OPTIONS = {
1587 load: (0, _wordpress_i18n.__)("Page load", "elementor"),
1588 scrollIn: (0, _wordpress_i18n.__)("Scroll into view", "elementor"),
1589 scrollOn: (0, _wordpress_i18n.__)("While scrolling", "elementor"),
1590 hover: (0, _wordpress_i18n.__)("On hover", "elementor"),
1591 click: (0, _wordpress_i18n.__)("On click", "elementor")
1592 };
1593 var BASE_TRIGGERS = ["load", "scrollIn"];
1594 function Trigger({ value, onChange }) {
1595 const baseOptions = Object.fromEntries(Object.entries(TRIGGER_OPTIONS).filter(([key]) => BASE_TRIGGERS.includes(key)));
1596 const disabledOptions = Object.fromEntries(Object.entries(TRIGGER_OPTIONS).filter(([key]) => !BASE_TRIGGERS.includes(key)));
1597 return /* @__PURE__ */ react.createElement(PromotionSelect, {
1598 value: value in baseOptions ? value : DEFAULT_VALUES.trigger,
1599 onChange,
1600 baseOptions,
1601 disabledOptions,
1602 promotionLabel: (0, _wordpress_i18n.__)("PRO triggers", "elementor"),
1603 promotionContent: (0, _wordpress_i18n.__)("Upgrade to unlock more interactions triggers.", "elementor"),
1604 upgradeUrl: "https://go.elementor.com/go-pro-interactions-triggers-modal/",
1605 trackingData: TRACKING_DATA
1606 });
1607 }
1608
1609 //#endregion
1610 //#region packages/packages/core/editor-interactions/src/hooks/on-duplicate.ts
1611 function initCleanInteractionIdsOnDuplicate() {
1612 (0, _elementor_editor_v1_adapters.registerDataHook)("after", "document/elements/duplicate", (_args, result) => {
1613 if (!result || typeof result === "boolean" && result === false) return;
1614 (Array.isArray(result) ? result : [result]).forEach((container) => {
1615 cleanInteractionIdsRecursive(container.id);
1616 });
1617 window.dispatchEvent(new CustomEvent("elementor/element/update_interactions"));
1618 });
1619 }
1620 function cleanInteractionIdsRecursive(elementId) {
1621 const container = (0, _elementor_editor_elements.getContainer)(elementId);
1622 if (!container) return;
1623 (0, _elementor_editor_elements.getAllDescendants)(container).forEach((element) => {
1624 cleanInteractionIds(element.id);
1625 });
1626 }
1627 function cleanInteractionIds(elementId) {
1628 const container = (0, _elementor_editor_elements.getContainer)(elementId);
1629 if (!container) return;
1630 const interactions = container.model.get("interactions");
1631 if (!interactions || !interactions.items) return;
1632 const updatedInteractions = structuredClone(interactions);
1633 updatedInteractions?.items?.forEach((interaction) => {
1634 if (interaction.$$type === "interaction-item" && interaction.value) interaction.value.interaction_id = createString(generateTempInteractionId());
1635 });
1636 container.model.set("interactions", updatedInteractions);
1637 }
1638
1639 //#endregion
1640 //#region packages/packages/core/editor-interactions/src/mcp/tools/schema.ts
1641 var baseSchema = {
1642 trigger: _elementor_schema.z.enum(["load", "scrollIn"]).optional().describe("Event that triggers the animation"),
1643 effect: _elementor_schema.z.enum([
1644 "fade",
1645 "slide",
1646 "scale"
1647 ]).optional().describe("Animation effect type"),
1648 effectType: _elementor_schema.z.enum(["in", "out"]).optional().describe("Whether the animation plays in or out"),
1649 direction: _elementor_schema.z.enum([
1650 "top",
1651 "bottom",
1652 "left",
1653 "right",
1654 "top-left",
1655 "top-right",
1656 "bottom-left",
1657 "bottom-right"
1658 ]).optional().describe("Direction of the Animation. Can be one of the following or empty if not needed. At slide effect, this is required field."),
1659 duration: _elementor_schema.z.number().min(0).max(1e4).optional().describe("Animation duration in milliseconds"),
1660 delay: _elementor_schema.z.number().min(0).max(1e4).optional().describe("Animation delay in milliseconds"),
1661 easing: _elementor_schema.z.enum(["easeIn"]).optional().describe("Easing function for the animation. Use \"easeIn\" for free tier."),
1662 excludedBreakpoints: _elementor_schema.z.array(_elementor_schema.z.enum([
1663 "widescreen",
1664 "desktop",
1665 "laptop",
1666 "tablet_extra",
1667 "tablet",
1668 "mobile_extra",
1669 "mobile"
1670 ])).optional().describe("Breakpoint IDs on which this interaction is disabled (e.g. [\"mobile\", \"tablet\"]). Fetch the \"elementor://breakpoints/list\" resource to get the valid IDs for the current site. Omit to enable on all breakpoints.")
1671 };
1672 var proSchema = {
1673 trigger: _elementor_schema.z.enum([
1674 "load",
1675 "scrollIn",
1676 "scrollOut",
1677 "scrollOn",
1678 "hover",
1679 "click"
1680 ]).optional().describe("Event that triggers the animation"),
1681 effect: _elementor_schema.z.enum([
1682 "fade",
1683 "slide",
1684 "scale",
1685 "custom"
1686 ]).optional().describe("Animation effect type"),
1687 easing: _elementor_schema.z.enum([
1688 "easeIn",
1689 "easeInOut",
1690 "easeOut",
1691 "backIn",
1692 "backInOut",
1693 "backOut",
1694 "linear"
1695 ]).optional().describe("Easing function for the animation."),
1696 customEffects: _elementor_schema.z.object({ keyframes: _elementor_schema.z.array(_elementor_schema.z.object({
1697 stop: _elementor_schema.z.number().describe("The stop of the keyframe in percent, can be either 0 or 100"),
1698 value: _elementor_schema.z.object({
1699 opacity: _elementor_schema.z.number().min(0).max(1).describe("The opacity of the keyframe"),
1700 scale: _elementor_schema.z.object({
1701 x: _elementor_schema.z.number().min(0).max(1).describe("The x scale of the keyframe"),
1702 y: _elementor_schema.z.number().min(0).max(1).describe("The y scale of the keyframe")
1703 }).optional().describe("The scale of the keyframe"),
1704 rotate: _elementor_schema.z.object({
1705 x: _elementor_schema.z.number().min(0).max(360).describe("The x rotate of the keyframe"),
1706 y: _elementor_schema.z.number().min(0).max(360).describe("The y rotate of the keyframe"),
1707 z: _elementor_schema.z.number().min(0).max(360).describe("The z rotate of the keyframe")
1708 }).optional().describe("The rotate of the keyframe"),
1709 move: _elementor_schema.z.object({
1710 x: _elementor_schema.z.number().min(0).max(1).describe("The x move of the keyframe"),
1711 y: _elementor_schema.z.number().min(0).max(1).describe("The y move of the keyframe"),
1712 z: _elementor_schema.z.number().min(0).max(1).describe("The z move of the keyframe")
1713 }).optional().describe("The move of the keyframe"),
1714 skew: _elementor_schema.z.object({
1715 x: _elementor_schema.z.number().min(0).max(360).describe("The x skew of the keyframe"),
1716 y: _elementor_schema.z.number().min(0).max(360).describe("The y skew of the keyframe")
1717 }).optional().describe("The skew of the keyframe")
1718 })
1719 })).describe("The keyframes of the custom effect") }).optional().describe("The custom effect to use for the animation")
1720 };
1721
1722 //#endregion
1723 //#region packages/packages/core/editor-interactions/src/mcp/resources/interactions-schema-resource.ts
1724 var INTERACTIONS_SCHEMA_URI = "elementor://interactions/schema";
1725 var initInteractionsSchemaResource = (reg) => {
1726 const { resource } = reg;
1727 const schema = (0, _elementor_utils.isProActive)() ? {
1728 ...baseSchema,
1729 ...proSchema
1730 } : baseSchema;
1731 resource("interactions-schema", INTERACTIONS_SCHEMA_URI, { description: "Schema describing all available options for element interactions." }, async () => {
1732 return { contents: [{
1733 uri: INTERACTIONS_SCHEMA_URI,
1734 mimeType: "application/json",
1735 text: JSON.stringify(schema)
1736 }] };
1737 });
1738 };
1739
1740 //#endregion
1741 //#region packages/packages/core/editor-interactions/src/mcp/constants.ts
1742 var MAX_INTERACTIONS_PER_ELEMENT = 5;
1743 var EDITOR_INTERACTIONS_MCP_SHORT_DESCRIPTION = `Everything related to V4 ( Atomic ) interactions.
1744 # Interactions
1745 - Create/update/delete interactions
1746 - Get list of interactions
1747 - Get details of an interaction
1748 `;
1749 var EDITOR_INTERACTIONS_MCP_DESCRIPTION = `MCP server for managing element interactions and animations. Use this to add, modify, or remove animations and motion effects triggered by user events such as page load or scroll-into-view.
1750 ** IMPORTANT **
1751 Use the "interactions-schema" resource to get the schema of the interactions.
1752 Actions:
1753 - get: Read the current interactions on the element.
1754 - add: Add a new interaction (max ${5} per element).
1755 - update: Update an existing interaction by its interactionId.
1756 - delete: Remove a specific interaction by its interactionId.
1757 - clear: Remove all interactions from the element.
1758
1759 For add/update, provide: trigger, effect, effectType, direction (required for slide effect), duration, delay, easing.
1760 Use excludedBreakpoints to disable the animation on specific responsive breakpoints (e.g. ["mobile", "tablet"]).
1761 Example Get Request:
1762 {
1763 "elementId": "123",
1764 "action": "get",
1765 "interactionId": "123",
1766 "animationData": {
1767 "trigger": "click",
1768 "effect": "fade",
1769 }
1770 }
1771 Example Add Request:
1772 {
1773 "elementId": "123",
1774 "action": "add",
1775 "animationData": {
1776 "effectType": "in",
1777 "direction": "top",
1778 "trigger": "click",
1779 "effect": "fade",
1780 "duration": 1000,
1781 "delay": 0,
1782 "easing": "easeIn",
1783 "excludedBreakpoints": ["mobile", "tablet"],
1784 }
1785 }
1786 Example Update Request:
1787 {
1788 "elementId": "123",
1789 "action": "update",
1790 "interactionId": "123",
1791 "animationData": {
1792 "trigger": "click",
1793 "effect": "fade",
1794 }
1795 }
1796 Example Delete Request:
1797 {
1798 "elementId": "123",
1799 "action": "delete",
1800 "interactionId": "123",
1801 }
1802 Example Clear Request:
1803 {
1804 "elementId": "123",
1805 "action": "clear",
1806 }`;
1807
1808 //#endregion
1809 //#region packages/packages/core/editor-interactions/src/mcp/tools/manage-element-interaction-tool.ts
1810 var EMPTY_INTERACTIONS = {
1811 version: 1,
1812 items: []
1813 };
1814 var EFFECTS_WITHOUT_TYPE = ["custom"];
1815 var BREAKPOINTS_SCHEMA_URI = "elementor://breakpoints/list";
1816 var initManageElementInteractionTool = (reg) => {
1817 const { addTool } = reg;
1818 const extendedSchema = (0, _elementor_utils.isProActive)() ? {
1819 ...baseSchema,
1820 ...proSchema
1821 } : baseSchema;
1822 addTool({
1823 name: "manage-element-interaction",
1824 description: `Manage the element interaction.`,
1825 schema: {
1826 elementId: _elementor_schema.z.string().describe("The ID of the element to read or modify interactions on"),
1827 action: _elementor_schema.z.enum([
1828 "get",
1829 "add",
1830 "update",
1831 "delete",
1832 "clear"
1833 ]).describe("Operation to perform. Use \"get\" first to inspect existing interactions."),
1834 interactionId: _elementor_schema.z.string().optional().describe("Interaction ID — required for update and delete. Obtain from a prior \"get\" call."),
1835 ...extendedSchema
1836 },
1837 requiredResources: [{
1838 uri: INTERACTIONS_SCHEMA_URI,
1839 description: "Interactions schema with all available options"
1840 }, {
1841 uri: BREAKPOINTS_SCHEMA_URI,
1842 description: "Available breakpoint IDs for excludedBreakpoints"
1843 }],
1844 isDestructive: true,
1845 outputSchema: {
1846 success: _elementor_schema.z.boolean().describe("Whether the action was successful"),
1847 action: _elementor_schema.z.enum([
1848 "get",
1849 "add",
1850 "update",
1851 "delete",
1852 "clear"
1853 ]).describe("Operation to perform. Use \"get\" first to inspect existing interactions."),
1854 elementId: _elementor_schema.z.string().optional().describe("The ID of the element to read or modify interactions on"),
1855 interactions: _elementor_schema.z.array(_elementor_schema.z.any()).optional().describe("The interactions on the element"),
1856 count: _elementor_schema.z.number().optional().describe("The number of interactions on the element")
1857 },
1858 handler: (input) => {
1859 const { elementId, action, interactionId, ...animationData } = input;
1860 const { effectType, ...restAnimationData } = animationData;
1861 const effect = restAnimationData.effect;
1862 const resolvedType = effectType ?? (effect && !EFFECTS_WITHOUT_TYPE.includes(effect) ? "in" : void 0);
1863 const currentInteractions = interactionsRepository.all().find((data) => data.elementId === elementId)?.interactions ?? EMPTY_INTERACTIONS;
1864 if (action === "get") {
1865 const summary = currentInteractions.items.map((item) => {
1866 const { value } = item;
1867 const animValue = value.animation.value;
1868 const timingValue = animValue.timing_config.value;
1869 const configValue = animValue.config.value;
1870 return {
1871 id: extractString(value.interaction_id),
1872 trigger: extractString(value.trigger),
1873 effect: extractString(animValue.effect),
1874 effectType: extractString(animValue.type),
1875 direction: extractString(animValue.direction),
1876 duration: extractSize(timingValue.duration),
1877 delay: extractSize(timingValue.delay),
1878 easing: extractString(configValue.easing),
1879 excludedBreakpoints: extractExcludedBreakpoints(value.breakpoints)
1880 };
1881 });
1882 return {
1883 success: true,
1884 elementId,
1885 action,
1886 interactions: summary,
1887 count: summary.length
1888 };
1889 }
1890 let updatedItems = [...currentInteractions.items];
1891 switch (action) {
1892 case "add": {
1893 if (updatedItems.length >= 5) throw new Error(`Cannot add more than ${5} interactions per element. Current count: ${updatedItems.length}. Delete an existing interaction first.`);
1894 const newItem = createInteractionItem({
1895 interactionId: generateTempInteractionId(),
1896 ...restAnimationData,
1897 type: resolvedType
1898 });
1899 updatedItems = [...updatedItems, newItem];
1900 break;
1901 }
1902 case "update": {
1903 if (!interactionId) throw new Error("interactionId is required for the update action.");
1904 const itemIndex = updatedItems.findIndex((item) => extractString(item.value.interaction_id) === interactionId);
1905 if (itemIndex === -1) throw new Error(`Interaction with ID "${interactionId}" not found on element "${elementId}".`);
1906 const updatedItem = createInteractionItem({
1907 interactionId,
1908 ...restAnimationData,
1909 type: resolvedType
1910 });
1911 updatedItems = [
1912 ...updatedItems.slice(0, itemIndex),
1913 updatedItem,
1914 ...updatedItems.slice(itemIndex + 1)
1915 ];
1916 break;
1917 }
1918 case "delete": {
1919 if (!interactionId) throw new Error("interactionId is required for the delete action.");
1920 const beforeCount = updatedItems.length;
1921 updatedItems = updatedItems.filter((item) => extractString(item.value.interaction_id) !== interactionId);
1922 if (updatedItems.length === beforeCount) throw new Error(`Interaction with ID "${interactionId}" not found on element "${elementId}".`);
1923 break;
1924 }
1925 case "clear":
1926 updatedItems = [];
1927 break;
1928 }
1929 const updatedInteractions = {
1930 ...currentInteractions,
1931 items: updatedItems
1932 };
1933 try {
1934 (0, _elementor_editor_elements.updateElementInteractions)({
1935 elementId,
1936 interactions: updatedInteractions
1937 });
1938 } catch (error) {
1939 throw new Error(`Failed to update interactions for element "${elementId}": ${error instanceof Error ? error.message : "Unknown error"}`);
1940 }
1941 return {
1942 success: true,
1943 action,
1944 elementId,
1945 count: updatedItems.length
1946 };
1947 }
1948 });
1949 };
1950
1951 //#endregion
1952 //#region packages/packages/core/editor-interactions/src/mcp/index.ts
1953 var initMcpInteractions = (reg) => {
1954 const { setMCPDescription } = reg;
1955 setMCPDescription(`Everything related to V4 ( Atomic ) interactions.
1956 # Interactions
1957 - Create/update/delete interactions
1958 - Get list of interactions
1959 - Get details of an interaction
1960 `);
1961 initInteractionsSchemaResource(reg);
1962 initManageElementInteractionTool(reg);
1963 };
1964
1965 //#endregion
1966 //#region packages/packages/core/editor-interactions/src/init.ts
1967 function init() {
1968 try {
1969 interactionsRepository.register(documentElementsInteractionsProvider);
1970 initCleanInteractionIdsOnDuplicate();
1971 initPasteInteractionsCommand();
1972 registerInteractionsControl({
1973 type: "trigger",
1974 component: Trigger,
1975 options: ["load", "scrollIn"]
1976 });
1977 registerInteractionsControl({
1978 type: "easing",
1979 component: Easing,
1980 options: ["easeIn"]
1981 });
1982 registerInteractionsControl({
1983 type: "replay",
1984 component: Replay,
1985 options: ["no"]
1986 });
1987 registerInteractionsControl({
1988 type: "effectType",
1989 component: EffectType,
1990 options: ["in", "out"]
1991 });
1992 registerInteractionsControl({
1993 type: "direction",
1994 component: Direction,
1995 options: [
1996 "top",
1997 "bottom",
1998 "left",
1999 "right"
2000 ]
2001 });
2002 registerInteractionsControl({
2003 type: "effect",
2004 component: Effect,
2005 options: [
2006 "fade",
2007 "slide",
2008 "scale"
2009 ]
2010 });
2011 registerInteractionsControl({
2012 type: "repeat",
2013 component: Repeat
2014 });
2015 initMcpInteractions((0, _elementor_editor_mcp.getMCPByDomain)("interactions", {
2016 docs: EDITOR_INTERACTIONS_MCP_DESCRIPTION,
2017 instructions: EDITOR_INTERACTIONS_MCP_SHORT_DESCRIPTION
2018 }));
2019 } catch (error) {
2020 throw error;
2021 }
2022 }
2023
2024 //#endregion
2025 //#region packages/packages/core/editor-interactions/src/index.ts
2026 var src_exports = /* @__PURE__ */ __exportAll({
2027 BASE_EASINGS: () => BASE_EASINGS,
2028 BASE_EFFECTS: () => BASE_EFFECTS,
2029 BASE_REPLAY: () => BASE_REPLAY,
2030 BASE_TRIGGERS: () => BASE_TRIGGERS,
2031 DEFAULT_VALUES: () => DEFAULT_VALUES,
2032 EASING_OPTIONS: () => EASING_OPTIONS,
2033 EFFECT_OPTIONS: () => EFFECT_OPTIONS,
2034 ELEMENTS_INTERACTIONS_PROVIDER_KEY_PREFIX: () => ELEMENTS_INTERACTIONS_PROVIDER_KEY_PREFIX,
2035 EmptyState: () => EmptyState,
2036 InteractionsTab: () => InteractionsTab,
2037 REPEAT_OPTIONS: () => REPEAT_OPTIONS,
2038 REPEAT_TOOLTIPS: () => REPEAT_TOOLTIPS,
2039 REPLAY_OPTIONS: () => REPLAY_OPTIONS,
2040 SCROLL_INTERACTION_EVENT: () => SCROLL_INTERACTION_EVENT,
2041 TRIGGER_OPTIONS: () => TRIGGER_OPTIONS,
2042 buildDisplayLabel: () => buildDisplayLabel,
2043 createAnimationPreset: () => createAnimationPreset,
2044 createBoolean: () => createBoolean,
2045 createConfig: () => createConfig,
2046 createDefaultInteractionItem: () => createDefaultInteractionItem,
2047 createDefaultInteractions: () => createDefaultInteractions,
2048 createExcludedBreakpoints: () => createExcludedBreakpoints,
2049 createInteractionBreakpoints: () => createInteractionBreakpoints,
2050 createInteractionItem: () => createInteractionItem,
2051 createInteractionsProvider: () => createInteractionsProvider,
2052 createNumber: () => createNumber,
2053 createString: () => createString,
2054 createTimingConfig: () => createTimingConfig,
2055 dispatchScrollInteraction: () => dispatchScrollInteraction,
2056 extractBoolean: () => extractBoolean,
2057 extractExcludedBreakpoints: () => extractExcludedBreakpoints,
2058 extractScrollOverlayParams: () => extractScrollOverlayParams,
2059 extractSize: () => extractSize,
2060 extractString: () => extractString,
2061 formatSizeValue: () => formatSizeValue,
2062 generateTempInteractionId: () => generateTempInteractionId,
2063 getInteractionsConfig: () => getInteractionsConfig,
2064 init: () => init,
2065 interactionsRepository: () => interactionsRepository,
2066 isTempId: () => isTempId,
2067 parseSizeValue: () => parseSizeValue,
2068 registerInteractionsControl: () => registerInteractionsControl,
2069 resolveDirection: () => resolveDirection,
2070 syncGridOverlay: () => syncGridOverlay,
2071 useElementInteractions: () => useElementInteractions
2072 });
2073
2074 //#endregion
2075 //#region \0elementor-package-library-entry
2076 (window.elementorV2 = window.elementorV2 || {}).editorInteractions = src_exports;
2077
2078 //#endregion
2079 })(React, elementorV2.icons, elementorV2.ui, wp.i18n, elementorV2.session, elementorV2.editorElements, elementorV2.editorV1Adapters, elementorV2.editorProps, elementorV2.editorControls, elementorV2.events, elementorV2.editorResponsive, elementorV2.editorMcp, elementorV2.editorUi, elementorV2.utils, elementorV2.schema);
2080 window.elementorV2.editorInteractions?.init?.();
2081 //# sourceMappingURL=editor-interactions.js.map