@elementor/editor-interactions 4.0.0-manual → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/index.d.mts +123 -5
  2. package/dist/index.d.ts +123 -5
  3. package/dist/index.js +861 -334
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +823 -312
  6. package/dist/index.mjs.map +1 -1
  7. package/package.json +12 -11
  8. package/src/commands/get-clipboard-elements.ts +11 -0
  9. package/src/commands/paste-interactions.ts +136 -0
  10. package/src/components/controls/easing.tsx +3 -0
  11. package/src/components/controls/effect.tsx +3 -0
  12. package/src/components/controls/repeat.tsx +57 -0
  13. package/src/components/controls/replay.tsx +15 -13
  14. package/src/components/controls/trigger.tsx +3 -0
  15. package/src/components/interaction-details.tsx +162 -120
  16. package/src/components/interactions-list.tsx +16 -3
  17. package/src/components/interactions-tab.tsx +4 -1
  18. package/src/contexts/interactions-context.tsx +4 -1
  19. package/src/hooks/use-element-interactions.ts +26 -0
  20. package/src/index.ts +26 -0
  21. package/src/init.ts +13 -3
  22. package/src/interactions-controls-registry.ts +15 -3
  23. package/src/mcp/constants.ts +58 -0
  24. package/src/mcp/index.ts +15 -69
  25. package/src/mcp/tools/manage-element-interaction-tool.ts +40 -5
  26. package/src/mcp/tools/schema.ts +1 -1
  27. package/src/types.ts +6 -1
  28. package/src/ui/interactions-promotion-chip.tsx +14 -6
  29. package/src/ui/promotion-overlay-layout.tsx +22 -0
  30. package/src/ui/promotion-select.tsx +4 -0
  31. package/src/utils/custom-effect-to-prop-value.ts +145 -0
  32. package/src/utils/filter-interactions.ts +9 -0
  33. package/src/utils/get-interactions-config.ts +1 -11
  34. package/src/utils/is-supported-interaction-item.ts +39 -0
  35. package/src/utils/prop-value-utils.ts +59 -34
  36. package/src/utils/tracking.ts +42 -0
package/dist/index.js CHANGED
@@ -39,13 +39,38 @@ __export(index_exports, {
39
39
  ELEMENTS_INTERACTIONS_PROVIDER_KEY_PREFIX: () => ELEMENTS_INTERACTIONS_PROVIDER_KEY_PREFIX,
40
40
  EmptyState: () => EmptyState,
41
41
  InteractionsTab: () => InteractionsTab,
42
+ REPEAT_OPTIONS: () => REPEAT_OPTIONS,
43
+ REPEAT_TOOLTIPS: () => REPEAT_TOOLTIPS,
42
44
  REPLAY_OPTIONS: () => REPLAY_OPTIONS,
43
45
  TRIGGER_OPTIONS: () => TRIGGER_OPTIONS,
46
+ buildDisplayLabel: () => buildDisplayLabel,
47
+ convertTimeUnit: () => convertTimeUnit,
48
+ createAnimationPreset: () => createAnimationPreset,
49
+ createBoolean: () => createBoolean,
50
+ createConfig: () => createConfig,
51
+ createDefaultInteractionItem: () => createDefaultInteractionItem,
52
+ createDefaultInteractions: () => createDefaultInteractions,
53
+ createExcludedBreakpoints: () => createExcludedBreakpoints,
54
+ createInteractionBreakpoints: () => createInteractionBreakpoints,
55
+ createInteractionItem: () => createInteractionItem,
44
56
  createInteractionsProvider: () => createInteractionsProvider,
57
+ createNumber: () => createNumber,
58
+ createString: () => createString,
59
+ createTimingConfig: () => createTimingConfig,
60
+ extractBoolean: () => extractBoolean,
61
+ extractExcludedBreakpoints: () => extractExcludedBreakpoints,
62
+ extractSize: () => extractSize,
63
+ extractString: () => extractString,
64
+ formatSizeValue: () => formatSizeValue,
65
+ generateTempInteractionId: () => generateTempInteractionId,
45
66
  getInteractionsConfig: () => getInteractionsConfig,
46
67
  init: () => init,
47
68
  interactionsRepository: () => interactionsRepository,
48
- registerInteractionsControl: () => registerInteractionsControl
69
+ isTempId: () => isTempId,
70
+ parseSizeValue: () => parseSizeValue,
71
+ registerInteractionsControl: () => registerInteractionsControl,
72
+ resolveDirection: () => resolveDirection,
73
+ useElementInteractions: () => useElementInteractions
49
74
  });
50
75
  module.exports = __toCommonJS(index_exports);
51
76
 
@@ -77,90 +102,34 @@ var EmptyState = ({ onCreateInteraction }) => {
77
102
 
78
103
  // src/components/interactions-tab.tsx
79
104
  var React11 = __toESM(require("react"));
80
- var import_react9 = require("react");
81
- var import_editor_elements2 = require("@elementor/editor-elements");
105
+ var import_react10 = require("react");
82
106
  var import_session = require("@elementor/session");
83
107
  var import_ui7 = require("@elementor/ui");
84
108
 
85
109
  // src/contexts/interactions-context.tsx
86
110
  var React2 = __toESM(require("react"));
87
- var import_react = require("react");
88
- var import_editor_elements = require("@elementor/editor-elements");
89
- var InteractionsContext = (0, import_react.createContext)(null);
90
- var DEFAULT_INTERACTIONS = {
91
- version: 1,
92
- items: []
93
- };
94
- var InteractionsProvider = ({ children, elementId }) => {
95
- const rawInteractions = (0, import_editor_elements.useElementInteractions)(elementId);
96
- (0, import_react.useEffect)(() => {
97
- window.dispatchEvent(new CustomEvent("elementor/element/update_interactions"));
98
- }, []);
99
- const interactions = rawInteractions ?? DEFAULT_INTERACTIONS;
100
- const setInteractions = (value) => {
101
- const normalizedValue = value && value.items?.length === 0 ? void 0 : value;
102
- (0, import_editor_elements.updateElementInteractions)({
103
- elementId,
104
- interactions: normalizedValue
105
- });
106
- };
107
- const playInteractions = (interactionId) => {
108
- (0, import_editor_elements.playElementInteractions)(elementId, interactionId);
109
- };
110
- const contextValue = {
111
- interactions,
112
- setInteractions,
113
- playInteractions
114
- };
115
- return /* @__PURE__ */ React2.createElement(InteractionsContext.Provider, { value: contextValue }, children);
116
- };
117
- var useInteractionsContext = () => {
118
- const context = (0, import_react.useContext)(InteractionsContext);
119
- if (!context) {
120
- throw new Error("useInteractionsContext must be used within InteractionsProvider");
121
- }
122
- return context;
123
- };
124
-
125
- // src/contexts/popup-state-context.tsx
126
- var React3 = __toESM(require("react"));
127
111
  var import_react2 = require("react");
128
- var PopupStateContext = (0, import_react2.createContext)(void 0);
129
- var PopupStateProvider = ({ children }) => {
130
- const [openByDefault, setOpenByDefault] = (0, import_react2.useState)(false);
131
- const triggerDefaultOpen = (0, import_react2.useCallback)(() => {
132
- setOpenByDefault(true);
133
- }, []);
134
- const resetDefaultOpen = (0, import_react2.useCallback)(() => {
135
- setOpenByDefault(false);
136
- }, []);
137
- return /* @__PURE__ */ React3.createElement(PopupStateContext.Provider, { value: { openByDefault, triggerDefaultOpen, resetDefaultOpen } }, children);
138
- };
112
+ var import_editor_elements2 = require("@elementor/editor-elements");
139
113
 
140
- // src/components/interactions-list.tsx
141
- var React10 = __toESM(require("react"));
142
- var import_react8 = require("react");
143
- var import_editor_controls5 = require("@elementor/editor-controls");
144
- var import_icons2 = require("@elementor/icons");
145
- var import_ui6 = require("@elementor/ui");
146
- var import_i18n5 = require("@wordpress/i18n");
114
+ // src/hooks/use-element-interactions.ts
115
+ var import_react = require("react");
116
+ var import_editor_elements = require("@elementor/editor-elements");
117
+ var import_editor_v1_adapters = require("@elementor/editor-v1-adapters");
147
118
 
148
- // src/contexts/interactions-item-context.tsx
149
- var React4 = __toESM(require("react"));
150
- var import_react3 = require("react");
151
- var InteractionItemContext = (0, import_react3.createContext)(null);
152
- function InteractionItemContextProvider({
153
- value,
154
- children
119
+ // src/interactions-controls-registry.ts
120
+ var controlsRegistry = /* @__PURE__ */ new Map();
121
+ function registerInteractionsControl({
122
+ type,
123
+ component,
124
+ options
155
125
  }) {
156
- return /* @__PURE__ */ React4.createElement(InteractionItemContext.Provider, { value }, children);
126
+ controlsRegistry.set(type, { type, component, options });
157
127
  }
158
- function useInteractionItemContext() {
159
- const context = (0, import_react3.useContext)(InteractionItemContext);
160
- if (!context) {
161
- throw new Error("useInteractionItemContext must be used within InteractionItemContextProvider");
162
- }
163
- return context;
128
+ function getInteractionsControl(type) {
129
+ return controlsRegistry.get(type);
130
+ }
131
+ function getInteractionsControlOptions(type) {
132
+ return controlsRegistry.get(type)?.options ?? [];
164
133
  }
165
134
 
166
135
  // src/utils/prop-value-utils.ts
@@ -219,17 +188,134 @@ var createSizeValue = (size, unit) => {
219
188
  return { size, unit };
220
189
  };
221
190
 
191
+ // src/utils/custom-effect-to-prop-value.ts
192
+ var CUSTOM_EFFECT_TYPE = "custom-effect";
193
+ var KEYFRAMES_TYPE = "keyframes";
194
+ var KEYFRAME_STOP_TYPE = "keyframe-stop";
195
+ var KEYFRAME_STOP_SETTINGS_TYPE = "keyframe-stop-settings";
196
+ var SIZE_TYPE = "size";
197
+ var NUMBER_TYPE = "number";
198
+ var TRANSFORM_SCALE_TYPE = "transform-scale";
199
+ var TRANSFORM_ROTATE_TYPE = "transform-rotate";
200
+ var TRANSFORM_MOVE_TYPE = "transform-move";
201
+ var TRANSFORM_SKEW_TYPE = "transform-skew";
202
+ var UNIT_PERCENT = "%";
203
+ var UNIT_DEG = "deg";
204
+ var UNIT_PX = "px";
205
+ var isPlainCustomEffect = (v) => typeof v === "object" && v !== null && "keyframes" in v && Array.isArray(v.keyframes) && !("$$type" in v);
206
+ var toSizePropValue = (size, unit = UNIT_PERCENT) => ({
207
+ $$type: SIZE_TYPE,
208
+ value: { size, unit }
209
+ });
210
+ var toNumberPropValue = (n) => ({
211
+ $$type: NUMBER_TYPE,
212
+ value: n
213
+ });
214
+ var toDimensionalNumberPropValue = (type, plain, defaults) => ({
215
+ $$type: type,
216
+ value: {
217
+ x: toNumberPropValue(plain.x ?? defaults.x),
218
+ y: toNumberPropValue(plain.y ?? defaults.y),
219
+ z: toNumberPropValue(plain.z ?? defaults.z)
220
+ }
221
+ });
222
+ var toDimensionalSizePropValue = (type, plain, defaults, unit) => ({
223
+ $$type: type,
224
+ value: {
225
+ x: toSizePropValue(plain.x ?? defaults.x, unit),
226
+ y: toSizePropValue(plain.y ?? defaults.y, unit),
227
+ z: toSizePropValue(plain.z ?? defaults.z, unit)
228
+ }
229
+ });
230
+ var toSkewPropValue = (plain) => ({
231
+ $$type: TRANSFORM_SKEW_TYPE,
232
+ value: {
233
+ x: toSizePropValue(plain.x ?? 0, UNIT_DEG),
234
+ y: toSizePropValue(plain.y ?? 0, UNIT_DEG)
235
+ }
236
+ });
237
+ var toKeyframeStopSettingsPropValue = (plain) => {
238
+ const value = {};
239
+ if (plain.opacity !== void 0) {
240
+ const percent = plain.opacity <= 1 ? Math.round(plain.opacity * 100) : plain.opacity;
241
+ value.opacity = toSizePropValue(percent);
242
+ }
243
+ if (plain.scale !== void 0) {
244
+ value.scale = toDimensionalNumberPropValue(TRANSFORM_SCALE_TYPE, plain.scale, { x: 1, y: 1, z: 1 });
245
+ }
246
+ if (plain.rotate !== void 0) {
247
+ value.rotate = toDimensionalSizePropValue(
248
+ TRANSFORM_ROTATE_TYPE,
249
+ plain.rotate,
250
+ { x: 0, y: 0, z: 0 },
251
+ UNIT_DEG
252
+ );
253
+ }
254
+ if (plain.move !== void 0) {
255
+ value.move = toDimensionalSizePropValue(TRANSFORM_MOVE_TYPE, plain.move, { x: 0, y: 0, z: 0 }, UNIT_PX);
256
+ }
257
+ if (plain.skew !== void 0) {
258
+ value.skew = toSkewPropValue(plain.skew);
259
+ }
260
+ return { $$type: KEYFRAME_STOP_SETTINGS_TYPE, value };
261
+ };
262
+ var isPlainKeyframe = (v) => typeof v === "object" && v !== null && "stop" in v && "value" in v && !("$$type" in v);
263
+ var toKeyframeStopPropValue = (item) => {
264
+ if (!isPlainKeyframe(item)) {
265
+ return item;
266
+ }
267
+ return {
268
+ $$type: KEYFRAME_STOP_TYPE,
269
+ value: {
270
+ stop: toSizePropValue(item.stop),
271
+ settings: toKeyframeStopSettingsPropValue(item.value)
272
+ }
273
+ };
274
+ };
275
+ var toKeyframesPropValue = (keyframes) => ({
276
+ $$type: KEYFRAMES_TYPE,
277
+ value: keyframes.map(toKeyframeStopPropValue)
278
+ });
279
+ var plainCustomEffectToPropValue = (plain) => ({
280
+ $$type: CUSTOM_EFFECT_TYPE,
281
+ value: {
282
+ keyframes: toKeyframesPropValue(plain.keyframes)
283
+ }
284
+ });
285
+ var toCustomEffectPropValue = (customEffects) => {
286
+ if (customEffects === void 0) {
287
+ return void 0;
288
+ }
289
+ if (isPlainCustomEffect(customEffects)) {
290
+ return plainCustomEffectToPropValue(customEffects);
291
+ }
292
+ return customEffects;
293
+ };
294
+
295
+ // src/utils/get-interactions-config.ts
296
+ function getInteractionsConfig() {
297
+ return window.ElementorInteractionsConfig ?? {};
298
+ }
299
+
222
300
  // src/utils/temp-id-utils.ts
223
301
  var TEMP_ID_PREFIX = "temp-";
302
+ var TEMP_ID_REGEX = /^temp-[a-z0-9]+$/i;
224
303
  function generateTempInteractionId() {
225
304
  return `${TEMP_ID_PREFIX}${Math.random().toString(36).substring(2, 11)}`;
226
305
  }
306
+ function isTempId(id) {
307
+ return !!id && TEMP_ID_REGEX.test(id);
308
+ }
227
309
 
228
310
  // src/utils/prop-value-utils.ts
229
311
  var createString = (value) => ({
230
312
  $$type: "string",
231
313
  value
232
314
  });
315
+ var createNumber = (value) => ({
316
+ $$type: "number",
317
+ value
318
+ });
233
319
  var createTimingConfig = (duration, delay) => ({
234
320
  $$type: "timing-config",
235
321
  value: {
@@ -244,7 +330,9 @@ var createBoolean = (value) => ({
244
330
  var createConfig = ({
245
331
  replay,
246
332
  easing = "easeIn",
247
- relativeTo = "",
333
+ relativeTo = "viewport",
334
+ repeat = "",
335
+ times = 1,
248
336
  start = 85,
249
337
  end = 15
250
338
  }) => ({
@@ -253,6 +341,8 @@ var createConfig = ({
253
341
  replay: createBoolean(replay),
254
342
  easing: createString(easing),
255
343
  relativeTo: createString(relativeTo),
344
+ repeat: createString(repeat),
345
+ times: createNumber(times),
256
346
  start: createSize(start, "%"),
257
347
  end: createSize(end, "%")
258
348
  }
@@ -288,26 +378,33 @@ var createAnimationPreset = ({
288
378
  replay = false,
289
379
  easing = "easeIn",
290
380
  relativeTo,
381
+ repeat,
382
+ times,
291
383
  start,
292
384
  end,
293
385
  customEffects
294
- }) => ({
295
- $$type: "animation-preset-props",
296
- value: {
297
- effect: createString(effect),
298
- custom_effect: customEffects,
299
- type: createString(type),
300
- direction: createString(direction ?? ""),
301
- timing_config: createTimingConfig(duration, delay),
302
- config: createConfig({
303
- replay,
304
- easing,
305
- relativeTo,
306
- start,
307
- end
308
- })
309
- }
310
- });
386
+ }) => {
387
+ const customEffectProp = toCustomEffectPropValue(customEffects);
388
+ return {
389
+ $$type: "animation-preset-props",
390
+ value: {
391
+ effect: createString(effect),
392
+ ...customEffectProp !== void 0 && { custom_effect: customEffectProp },
393
+ type: createString(type),
394
+ direction: createString(direction ?? ""),
395
+ timing_config: createTimingConfig(duration, delay),
396
+ config: createConfig({
397
+ replay,
398
+ easing,
399
+ relativeTo,
400
+ repeat,
401
+ times,
402
+ start,
403
+ end
404
+ })
405
+ }
406
+ };
407
+ };
311
408
  var createInteractionItem = ({
312
409
  trigger,
313
410
  effect,
@@ -319,6 +416,8 @@ var createInteractionItem = ({
319
416
  replay = false,
320
417
  easing = "easeIn",
321
418
  relativeTo,
419
+ repeat,
420
+ times,
322
421
  start,
323
422
  end,
324
423
  excludedBreakpoints,
@@ -337,6 +436,8 @@ var createInteractionItem = ({
337
436
  replay,
338
437
  easing,
339
438
  relativeTo,
439
+ repeat,
440
+ times,
340
441
  start,
341
442
  end,
342
443
  customEffects
@@ -347,17 +448,22 @@ var createInteractionItem = ({
347
448
  }
348
449
  });
349
450
  var createDefaultInteractionItem = () => {
451
+ const { constants } = getInteractionsConfig();
350
452
  return createInteractionItem({
351
453
  trigger: "load",
352
454
  effect: "fade",
353
455
  type: "in",
354
- duration: 600,
355
- delay: 0,
456
+ duration: constants.defaultDuration,
457
+ delay: constants.defaultDelay,
356
458
  replay: false,
357
- easing: "easeIn",
459
+ easing: constants.defaultEasing,
358
460
  interactionId: generateTempInteractionId()
359
461
  });
360
462
  };
463
+ var createDefaultInteractions = () => ({
464
+ version: 1,
465
+ items: [createDefaultInteractionItem()]
466
+ });
361
467
  var extractString = (prop, fallback = "") => {
362
468
  return prop?.value ?? fallback;
363
469
  };
@@ -382,36 +488,193 @@ var buildDisplayLabel = (item) => {
382
488
  const type = extractString(item.animation.value.type);
383
489
  const triggerLabel = TRIGGER_LABELS[trigger] || capitalize(trigger);
384
490
  const effectLabel = capitalize(effect);
385
- const typeLabel = capitalize(type);
491
+ const typeLabel = "custom" === effect ? "" : capitalize(type);
386
492
  return `${triggerLabel}: ${effectLabel} ${typeLabel}`;
387
493
  };
388
494
 
495
+ // src/utils/is-supported-interaction-item.ts
496
+ function isSupportedInteractionItem(interaction) {
497
+ const value = interaction.value;
498
+ const replay = extractBoolean(value.animation.value.config?.value.replay);
499
+ if (true === replay) {
500
+ return hasSupport("replay", "yes");
501
+ }
502
+ const trigger = extractString(value.trigger);
503
+ const easing = extractString(value.animation.value.config?.value.easing);
504
+ const effect = extractString(value.animation.value.effect);
505
+ const checks = [
506
+ ["trigger", trigger],
507
+ ["easing", easing],
508
+ ["effect", effect]
509
+ ];
510
+ return checks.every(([controlType, controlValue]) => {
511
+ if (controlValue === "" || controlValue === null) {
512
+ return true;
513
+ }
514
+ return hasSupport(controlType, controlValue);
515
+ });
516
+ }
517
+ function hasSupport(controlType, controlValue) {
518
+ const supportedOptions = getInteractionsControlOptions(controlType);
519
+ if (1 > supportedOptions.length) {
520
+ return true;
521
+ }
522
+ return supportedOptions.includes(controlValue);
523
+ }
524
+
525
+ // src/utils/filter-interactions.ts
526
+ var filterInteractions = (interactions) => {
527
+ return interactions.filter((interaction) => {
528
+ return isSupportedInteractionItem(interaction);
529
+ });
530
+ };
531
+
532
+ // src/hooks/use-element-interactions.ts
533
+ var useElementInteractions = (elementId) => {
534
+ const [interactions, setInteractions] = (0, import_react.useState)(() => {
535
+ const initial = (0, import_editor_elements.getElementInteractions)(elementId);
536
+ const filteredInteractions = filterInteractions(initial?.items ?? []);
537
+ return { version: initial?.version ?? 1, items: filteredInteractions };
538
+ });
539
+ (0, import_editor_v1_adapters.__privateUseListenTo)(
540
+ (0, import_editor_v1_adapters.windowEvent)("elementor/element/update_interactions"),
541
+ () => {
542
+ const newInteractions = (0, import_editor_elements.getElementInteractions)(elementId);
543
+ const filteredInteractions = filterInteractions(newInteractions?.items ?? []);
544
+ setInteractions({ version: newInteractions?.version ?? 1, items: filteredInteractions });
545
+ },
546
+ [elementId]
547
+ );
548
+ return interactions;
549
+ };
550
+
551
+ // src/contexts/interactions-context.tsx
552
+ var InteractionsContext = (0, import_react2.createContext)(null);
553
+ var DEFAULT_INTERACTIONS = {
554
+ version: 1,
555
+ items: []
556
+ };
557
+ var InteractionsProvider = ({ children, elementId }) => {
558
+ const rawInteractions = useElementInteractions(elementId);
559
+ (0, import_react2.useEffect)(() => {
560
+ window.dispatchEvent(new CustomEvent("elementor/element/update_interactions"));
561
+ }, []);
562
+ const interactions = rawInteractions ?? DEFAULT_INTERACTIONS;
563
+ const setInteractions = (value) => {
564
+ const normalizedValue = value && value.items?.length === 0 ? void 0 : value;
565
+ (0, import_editor_elements2.updateElementInteractions)({
566
+ elementId,
567
+ interactions: normalizedValue
568
+ });
569
+ };
570
+ const playInteractions = (interactionId) => {
571
+ (0, import_editor_elements2.playElementInteractions)(elementId, interactionId);
572
+ };
573
+ const contextValue = {
574
+ elementId,
575
+ interactions,
576
+ setInteractions,
577
+ playInteractions
578
+ };
579
+ return /* @__PURE__ */ React2.createElement(InteractionsContext.Provider, { value: contextValue }, children);
580
+ };
581
+ var useInteractionsContext = () => {
582
+ const context = (0, import_react2.useContext)(InteractionsContext);
583
+ if (!context) {
584
+ throw new Error("useInteractionsContext must be used within InteractionsProvider");
585
+ }
586
+ return context;
587
+ };
588
+
589
+ // src/contexts/popup-state-context.tsx
590
+ var React3 = __toESM(require("react"));
591
+ var import_react3 = require("react");
592
+ var PopupStateContext = (0, import_react3.createContext)(void 0);
593
+ var PopupStateProvider = ({ children }) => {
594
+ const [openByDefault, setOpenByDefault] = (0, import_react3.useState)(false);
595
+ const triggerDefaultOpen = (0, import_react3.useCallback)(() => {
596
+ setOpenByDefault(true);
597
+ }, []);
598
+ const resetDefaultOpen = (0, import_react3.useCallback)(() => {
599
+ setOpenByDefault(false);
600
+ }, []);
601
+ return /* @__PURE__ */ React3.createElement(PopupStateContext.Provider, { value: { openByDefault, triggerDefaultOpen, resetDefaultOpen } }, children);
602
+ };
603
+
604
+ // src/utils/tracking.ts
605
+ var import_editor_elements3 = require("@elementor/editor-elements");
606
+ var import_events = require("@elementor/events");
607
+ var TRIGGER_LABELS2 = {
608
+ load: "On page load",
609
+ scrollIn: "Scroll into view",
610
+ scrollOut: "Scroll out of view",
611
+ scrollOn: "While scrolling",
612
+ hover: "Hover",
613
+ click: "Click"
614
+ };
615
+ var capitalize2 = (s) => s.charAt(0).toUpperCase() + s.slice(1);
616
+ var trackInteractionCreated = (elementId, item) => {
617
+ const { dispatchEvent, config } = (0, import_events.getMixpanel)();
618
+ if (!config?.names?.interactions?.created) {
619
+ return;
620
+ }
621
+ const trigger = extractString(item.value.trigger);
622
+ const effect = extractString(item.value.animation.value.effect);
623
+ const type = extractString(item.value.animation.value.type);
624
+ dispatchEvent?.(config.names.interactions.created, {
625
+ app_type: config?.appTypes?.editor,
626
+ window_name: config?.appTypes?.editor,
627
+ interaction_type: config?.triggers?.click,
628
+ target_name: (0, import_editor_elements3.getElementLabel)(elementId),
629
+ interaction_result: "interaction_created",
630
+ target_location: config?.locations?.widgetPanel,
631
+ location_l1: (0, import_editor_elements3.getElementLabel)(elementId),
632
+ location_l2: "interactions",
633
+ interaction_description: "interaction_created",
634
+ interaction_trigger: TRIGGER_LABELS2[trigger] ?? capitalize2(trigger),
635
+ interaction_effect: effect === "custom" ? capitalize2(effect) : `${capitalize2(effect)} ${capitalize2(type)}`
636
+ });
637
+ };
638
+
639
+ // src/components/interactions-list.tsx
640
+ var React10 = __toESM(require("react"));
641
+ var import_react9 = require("react");
642
+ var import_editor_controls5 = require("@elementor/editor-controls");
643
+ var import_icons2 = require("@elementor/icons");
644
+ var import_ui6 = require("@elementor/ui");
645
+ var import_i18n5 = require("@wordpress/i18n");
646
+
647
+ // src/contexts/interactions-item-context.tsx
648
+ var React4 = __toESM(require("react"));
649
+ var import_react4 = require("react");
650
+ var InteractionItemContext = (0, import_react4.createContext)(null);
651
+ function InteractionItemContextProvider({
652
+ value,
653
+ children
654
+ }) {
655
+ return /* @__PURE__ */ React4.createElement(InteractionItemContext.Provider, { value }, children);
656
+ }
657
+ function useInteractionItemContext() {
658
+ const context = (0, import_react4.useContext)(InteractionItemContext);
659
+ if (!context) {
660
+ throw new Error("useInteractionItemContext must be used within InteractionItemContextProvider");
661
+ }
662
+ return context;
663
+ }
664
+
389
665
  // src/components/interactions-list-item.tsx
390
666
  var React9 = __toESM(require("react"));
391
- var import_react7 = require("react");
667
+ var import_react8 = require("react");
392
668
  var import_ui5 = require("@elementor/ui");
393
669
  var import_i18n4 = require("@wordpress/i18n");
394
670
 
395
671
  // src/components/interaction-details.tsx
396
672
  var React7 = __toESM(require("react"));
397
- var import_react5 = require("react");
673
+ var import_react6 = require("react");
398
674
  var import_editor_controls3 = require("@elementor/editor-controls");
399
675
  var import_ui3 = require("@elementor/ui");
400
676
  var import_i18n2 = require("@wordpress/i18n");
401
677
 
402
- // src/interactions-controls-registry.ts
403
- var controlsRegistry = /* @__PURE__ */ new Map();
404
- function registerInteractionsControl({
405
- type,
406
- component,
407
- options
408
- }) {
409
- controlsRegistry.set(type, { type, component, options });
410
- }
411
- function getInteractionsControl(type) {
412
- return controlsRegistry.get(type);
413
- }
414
-
415
678
  // src/utils/resolve-direction.ts
416
679
  var resolveDirection = (hasDirection, newEffect, newDirection, currentDirection, currentEffect) => {
417
680
  if (newEffect === "slide" && !newDirection) {
@@ -428,7 +691,7 @@ var resolveDirection = (hasDirection, newEffect, newDirection, currentDirection,
428
691
 
429
692
  // src/components/controls/time-frame-indicator.tsx
430
693
  var React5 = __toESM(require("react"));
431
- var import_react4 = require("react");
694
+ var import_react5 = require("react");
432
695
  var import_editor_controls = require("@elementor/editor-controls");
433
696
 
434
697
  // src/utils/time-conversion.ts
@@ -447,8 +710,8 @@ function TimeFrameIndicator({
447
710
  defaultValue
448
711
  }) {
449
712
  const sizeValue = parseSizeValue(value, TIME_UNITS, defaultValue, DEFAULT_TIME_UNIT);
450
- const prevUnitRef = (0, import_react4.useRef)(sizeValue.unit);
451
- const setValue = (0, import_react4.useCallback)(
713
+ const prevUnitRef = (0, import_react5.useRef)(sizeValue.unit);
714
+ const setValue = (0, import_react5.useCallback)(
452
715
  (size) => {
453
716
  const unitChanged = prevUnitRef.current !== size.unit;
454
717
  if (unitChanged) {
@@ -504,6 +767,8 @@ var DEFAULT_VALUES = {
504
767
  replay: false,
505
768
  easing: "easeIn",
506
769
  relativeTo: "viewport",
770
+ repeat: "",
771
+ times: 1,
507
772
  start: 85,
508
773
  end: 15
509
774
  };
@@ -516,6 +781,8 @@ var controlVisibilityConfig = {
516
781
  relativeTo: (values) => values.trigger === "scrollOn",
517
782
  start: (values) => values.trigger === "scrollOn",
518
783
  end: (values) => values.trigger === "scrollOn",
784
+ repeat: (values) => values.trigger !== "scrollOn",
785
+ times: (values) => values.trigger !== "scrollOn" && values.repeat === "times",
519
786
  duration: (values) => {
520
787
  const isRelativeToVisible = values.trigger === "scrollOn";
521
788
  return !isRelativeToVisible;
@@ -525,8 +792,15 @@ var controlVisibilityConfig = {
525
792
  return !isRelativeToVisible;
526
793
  }
527
794
  };
795
+ function normalizeTimesValue(value, fallback) {
796
+ const numericValue = Number(value);
797
+ if (!Number.isFinite(numericValue)) {
798
+ return fallback;
799
+ }
800
+ return Math.max(1, Math.floor(numericValue));
801
+ }
528
802
  function useControlComponent(controlName, isVisible = true) {
529
- return (0, import_react5.useMemo)(() => {
803
+ return (0, import_react6.useMemo)(() => {
530
804
  if (!isVisible) {
531
805
  return null;
532
806
  }
@@ -544,6 +818,9 @@ var InteractionDetails = ({ interaction, onChange, onPlayInteraction }) => {
544
818
  const replay = extractBoolean(interaction.animation.value.config?.value.replay, DEFAULT_VALUES.replay);
545
819
  const easing = extractString(interaction.animation.value.config?.value.easing, DEFAULT_VALUES.easing);
546
820
  const relativeTo = extractString(interaction.animation.value.config?.value.relativeTo, DEFAULT_VALUES.relativeTo);
821
+ const configValue = interaction.animation.value.config?.value;
822
+ const repeat = extractString(configValue?.repeat, DEFAULT_VALUES.repeat);
823
+ const times = normalizeTimesValue(configValue?.times?.value, DEFAULT_VALUES.times);
547
824
  const start = extractSize(interaction.animation.value.config?.value.start, DEFAULT_VALUES.start);
548
825
  const end = extractSize(interaction.animation.value.config?.value.end, DEFAULT_VALUES.end);
549
826
  const interactionValues = {
@@ -556,6 +833,8 @@ var InteractionDetails = ({ interaction, onChange, onPlayInteraction }) => {
556
833
  easing,
557
834
  replay,
558
835
  relativeTo,
836
+ repeat,
837
+ times,
559
838
  start,
560
839
  end,
561
840
  customEffects
@@ -578,8 +857,15 @@ var InteractionDetails = ({ interaction, onChange, onPlayInteraction }) => {
578
857
  controlVisibilityConfig.effectType(interactionValues)
579
858
  );
580
859
  const DirectionControl = useControlComponent("direction", controlVisibilityConfig.direction(interactionValues));
860
+ const RepeatControl = useControlComponent(
861
+ "repeat",
862
+ controlVisibilityConfig.repeat(interactionValues)
863
+ );
864
+ const TimesControl = useControlComponent(
865
+ "times",
866
+ controlVisibilityConfig.times(interactionValues)
867
+ );
581
868
  const EasingControl = useControlComponent("easing");
582
- const containerRef = (0, import_react5.useRef)(null);
583
869
  const updateInteraction = (updates) => {
584
870
  const resolvedDirectionValue = resolveDirection(
585
871
  "direction" in updates,
@@ -601,6 +887,8 @@ var InteractionDetails = ({ interaction, onChange, onPlayInteraction }) => {
601
887
  replay: updates.replay ?? replay,
602
888
  easing: updates.easing ?? easing,
603
889
  relativeTo: updates.relativeTo ?? relativeTo,
890
+ repeat: updates.repeat ?? repeat,
891
+ times: updates.times ?? times,
604
892
  start: updates.start ?? start,
605
893
  end: updates.end ?? end,
606
894
  customEffects: updates.customEffects ?? customEffects
@@ -612,19 +900,12 @@ var InteractionDetails = ({ interaction, onChange, onPlayInteraction }) => {
612
900
  onPlayInteraction(interactionId);
613
901
  }, 0);
614
902
  };
615
- return /* @__PURE__ */ React7.createElement(import_ui3.Box, { ref: containerRef }, /* @__PURE__ */ React7.createElement(import_editor_controls3.PopoverContent, { p: 1.5 }, /* @__PURE__ */ React7.createElement(import_ui3.Grid, { container: true, spacing: 1.5 }, TriggerControl && /* @__PURE__ */ React7.createElement(Field, { label: (0, import_i18n2.__)("Trigger", "elementor") }, /* @__PURE__ */ React7.createElement(
616
- TriggerControl,
617
- {
618
- value: trigger,
619
- onChange: (v) => updateInteraction({ trigger: v })
620
- }
621
- )), ReplayControl && /* @__PURE__ */ React7.createElement(Field, { label: (0, import_i18n2.__)("Replay", "elementor") }, /* @__PURE__ */ React7.createElement(
903
+ return /* @__PURE__ */ React7.createElement(import_editor_controls3.PopoverContent, { p: 1.5 }, /* @__PURE__ */ React7.createElement(import_ui3.Grid, { container: true, spacing: 1.5 }, TriggerControl && /* @__PURE__ */ React7.createElement(Field, { label: (0, import_i18n2.__)("Trigger", "elementor") }, /* @__PURE__ */ React7.createElement(TriggerControl, { value: trigger, onChange: (v) => updateInteraction({ trigger: v }) })), ReplayControl && /* @__PURE__ */ React7.createElement(Field, { label: (0, import_i18n2.__)("Replay", "elementor") }, /* @__PURE__ */ React7.createElement(
622
904
  ReplayControl,
623
905
  {
624
906
  value: replay,
625
907
  onChange: (v) => updateInteraction({ replay: v }),
626
- disabled: true,
627
- anchorRef: containerRef
908
+ disabled: true
628
909
  }
629
910
  ))), /* @__PURE__ */ React7.createElement(import_ui3.Divider, null), /* @__PURE__ */ React7.createElement(import_ui3.Grid, { container: true, spacing: 1.5 }, EffectControl && /* @__PURE__ */ React7.createElement(Field, { label: (0, import_i18n2.__)("Effect", "elementor") }, /* @__PURE__ */ React7.createElement(EffectControl, { value: effect, onChange: (v) => updateInteraction({ effect: v }) })), CustomEffectControl && /* @__PURE__ */ React7.createElement(Field, { label: (0, import_i18n2.__)("Custom Effect", "elementor") }, /* @__PURE__ */ React7.createElement(
630
911
  CustomEffectControl,
@@ -639,6 +920,14 @@ var InteractionDetails = ({ interaction, onChange, onPlayInteraction }) => {
639
920
  onChange: (v) => updateInteraction({ direction: v }),
640
921
  interactionType: type
641
922
  }
923
+ )), RepeatControl && /* @__PURE__ */ React7.createElement(Field, { label: (0, import_i18n2.__)("Repeat", "elementor") }, /* @__PURE__ */ React7.createElement(RepeatControl, { value: repeat, onChange: (v) => updateInteraction({ repeat: v }) })), TimesControl && /* @__PURE__ */ React7.createElement(Field, { label: (0, import_i18n2.__)("Times", "elementor") }, /* @__PURE__ */ React7.createElement(
924
+ TimesControl,
925
+ {
926
+ value: times,
927
+ onChange: (v) => updateInteraction({
928
+ times: normalizeTimesValue(v, DEFAULT_VALUES.times)
929
+ })
930
+ }
642
931
  )), controlVisibilityConfig.duration(interactionValues) && /* @__PURE__ */ React7.createElement(Field, { label: (0, import_i18n2.__)("Duration", "elementor") }, /* @__PURE__ */ React7.createElement(
643
932
  TimeFrameIndicator,
644
933
  {
@@ -679,12 +968,12 @@ var InteractionDetails = ({ interaction, onChange, onPlayInteraction }) => {
679
968
  updateInteraction({ easing: v });
680
969
  }
681
970
  }
682
- )))));
971
+ ))));
683
972
  };
684
973
 
685
974
  // src/components/interaction-settings.tsx
686
975
  var React8 = __toESM(require("react"));
687
- var import_react6 = require("react");
976
+ var import_react7 = require("react");
688
977
  var import_editor_controls4 = require("@elementor/editor-controls");
689
978
  var import_editor_responsive = require("@elementor/editor-responsive");
690
979
  var import_ui4 = require("@elementor/ui");
@@ -692,11 +981,11 @@ var import_i18n3 = require("@wordpress/i18n");
692
981
  var SIZE = "tiny";
693
982
  var InteractionSettings = ({ interaction, onChange }) => {
694
983
  const breakpoints = (0, import_editor_responsive.useBreakpoints)();
695
- const availableBreakpoints = (0, import_react6.useMemo)(
984
+ const availableBreakpoints = (0, import_react7.useMemo)(
696
985
  () => breakpoints.map((breakpoint) => ({ label: breakpoint.label, value: String(breakpoint.id) })),
697
986
  [breakpoints]
698
987
  );
699
- const [selectedBreakpoints, setSelectedBreakpoints] = (0, import_react6.useState)(() => {
988
+ const [selectedBreakpoints, setSelectedBreakpoints] = (0, import_react7.useState)(() => {
700
989
  const excluded = extractExcludedBreakpoints(interaction.breakpoints).filter((excludedBreakpoint) => {
701
990
  return availableBreakpoints.some(({ value }) => value === excludedBreakpoint);
702
991
  });
@@ -704,7 +993,7 @@ var InteractionSettings = ({ interaction, onChange }) => {
704
993
  return !excluded.includes(value);
705
994
  });
706
995
  });
707
- const handleBreakpointChange = (0, import_react6.useCallback)(
996
+ const handleBreakpointChange = (0, import_react7.useCallback)(
708
997
  (_, newValue) => {
709
998
  setSelectedBreakpoints(newValue);
710
999
  const selectedValues = newValue.map((option) => option.value);
@@ -748,13 +1037,13 @@ var InteractionsListItem = ({
748
1037
  }) => {
749
1038
  const { getTabsProps, getTabProps, getTabPanelProps } = (0, import_ui5.useTabs)("details");
750
1039
  const context = useInteractionItemContext();
751
- const handleChange = (0, import_react7.useCallback)(
1040
+ const handleChange = (0, import_react8.useCallback)(
752
1041
  (newInteractionValue) => {
753
1042
  context?.onInteractionChange(index, newInteractionValue);
754
1043
  },
755
1044
  [context, index]
756
1045
  );
757
- const handlePlayInteraction = (0, import_react7.useCallback)(
1046
+ const handlePlayInteraction = (0, import_react8.useCallback)(
758
1047
  (interactionId2) => {
759
1048
  context?.onPlayInteraction(interactionId2);
760
1049
  },
@@ -793,14 +1082,15 @@ var InteractionsListItem = ({
793
1082
  var MAX_NUMBER_OF_INTERACTIONS = 5;
794
1083
  function InteractionsList(props) {
795
1084
  const { interactions, onSelectInteractions, onPlayInteraction, triggerCreateOnShowEmpty } = props;
796
- const hasInitializedRef = (0, import_react8.useRef)(false);
797
- const handleUpdateInteractions = (0, import_react8.useCallback)(
1085
+ const { elementId } = useInteractionsContext();
1086
+ const hasInitializedRef = (0, import_react9.useRef)(false);
1087
+ const handleUpdateInteractions = (0, import_react9.useCallback)(
798
1088
  (newInteractions) => {
799
1089
  onSelectInteractions(newInteractions);
800
1090
  },
801
1091
  [onSelectInteractions]
802
1092
  );
803
- (0, import_react8.useEffect)(() => {
1093
+ (0, import_react9.useEffect)(() => {
804
1094
  if (triggerCreateOnShowEmpty && !hasInitializedRef.current && (!interactions.items || interactions.items?.length === 0)) {
805
1095
  hasInitializedRef.current = true;
806
1096
  const newState = {
@@ -810,23 +1100,29 @@ function InteractionsList(props) {
810
1100
  handleUpdateInteractions(newState);
811
1101
  }
812
1102
  }, [triggerCreateOnShowEmpty, interactions.items, handleUpdateInteractions]);
813
- const isMaxNumberOfInteractionsReached = (0, import_react8.useMemo)(() => {
1103
+ const isMaxNumberOfInteractionsReached = (0, import_react9.useMemo)(() => {
814
1104
  return interactions.items?.length >= MAX_NUMBER_OF_INTERACTIONS;
815
1105
  }, [interactions.items?.length]);
816
1106
  const infotipContent = isMaxNumberOfInteractionsReached ? /* @__PURE__ */ React10.createElement(import_ui6.Alert, { color: "secondary", icon: /* @__PURE__ */ React10.createElement(import_icons2.InfoCircleFilledIcon, null), size: "small" }, /* @__PURE__ */ React10.createElement(import_ui6.AlertTitle, null, (0, import_i18n5.__)("Interactions", "elementor")), /* @__PURE__ */ React10.createElement(import_ui6.Box, { component: "span" }, (0, import_i18n5.__)(
817
1107
  "You've reached the limit of 5 interactions for this element. Please remove an interaction before creating a new one.",
818
1108
  "elementor"
819
1109
  ))) : void 0;
820
- const handleRepeaterChange = (0, import_react8.useCallback)(
821
- (newItems) => {
1110
+ const handleRepeaterChange = (0, import_react9.useCallback)(
1111
+ (newItems, _, meta) => {
822
1112
  handleUpdateInteractions({
823
1113
  ...interactions,
824
1114
  items: newItems
825
1115
  });
1116
+ if (meta?.action?.type === "add") {
1117
+ const addedItem = meta.action.payload[0]?.item;
1118
+ if (addedItem) {
1119
+ trackInteractionCreated(elementId, addedItem);
1120
+ }
1121
+ }
826
1122
  },
827
- [interactions, handleUpdateInteractions]
1123
+ [interactions, handleUpdateInteractions, elementId]
828
1124
  );
829
- const handleInteractionChange = (0, import_react8.useCallback)(
1125
+ const handleInteractionChange = (0, import_react9.useCallback)(
830
1126
  (index, newInteractionValue) => {
831
1127
  const newItems = structuredClone(interactions.items);
832
1128
  newItems[index] = {
@@ -840,7 +1136,7 @@ function InteractionsList(props) {
840
1136
  },
841
1137
  [interactions, handleUpdateInteractions]
842
1138
  );
843
- const contextValue = (0, import_react8.useMemo)(
1139
+ const contextValue = (0, import_react9.useMemo)(
844
1140
  () => ({
845
1141
  onInteractionChange: handleInteractionChange,
846
1142
  onPlayInteraction
@@ -884,14 +1180,15 @@ var InteractionsTab = ({ elementId }) => {
884
1180
  return /* @__PURE__ */ React11.createElement(PopupStateProvider, null, /* @__PURE__ */ React11.createElement(InteractionsTabContent, { elementId }));
885
1181
  };
886
1182
  function InteractionsTabContent({ elementId }) {
887
- const existingInteractions = (0, import_editor_elements2.useElementInteractions)(elementId);
888
- const firstInteractionState = (0, import_react9.useState)(false);
1183
+ const existingInteractions = useElementInteractions(elementId);
1184
+ const firstInteractionState = (0, import_react10.useState)(false);
889
1185
  const hasInteractions = existingInteractions?.items?.length || firstInteractionState[0];
890
1186
  return /* @__PURE__ */ React11.createElement(import_session.SessionStorageProvider, { prefix: elementId }, hasInteractions ? /* @__PURE__ */ React11.createElement(InteractionsProvider, { elementId }, /* @__PURE__ */ React11.createElement(InteractionsContent, { firstInteractionState })) : /* @__PURE__ */ React11.createElement(
891
1187
  EmptyState,
892
1188
  {
893
1189
  onCreateInteraction: () => {
894
1190
  firstInteractionState[1](true);
1191
+ trackInteractionCreated(elementId, createDefaultInteractionItem());
895
1192
  }
896
1193
  }
897
1194
  ));
@@ -900,7 +1197,7 @@ function InteractionsContent({
900
1197
  firstInteractionState
901
1198
  }) {
902
1199
  const { interactions, setInteractions, playInteractions } = useInteractionsContext();
903
- const applyInteraction = (0, import_react9.useCallback)(
1200
+ const applyInteraction = (0, import_react10.useCallback)(
904
1201
  (newInteractions) => {
905
1202
  firstInteractionState[1](false);
906
1203
  if (!newInteractions) {
@@ -922,20 +1219,6 @@ function InteractionsContent({
922
1219
  ));
923
1220
  }
924
1221
 
925
- // src/utils/get-interactions-config.ts
926
- var DEFAULT_CONFIG = {
927
- constants: {
928
- defaultDuration: 300,
929
- defaultDelay: 0,
930
- slideDistance: 100,
931
- scaleStart: 0.5,
932
- easing: "linear"
933
- }
934
- };
935
- function getInteractionsConfig() {
936
- return window.ElementorInteractionsConfig || DEFAULT_CONFIG;
937
- }
938
-
939
1222
  // src/utils/create-interactions-repository.ts
940
1223
  var createInteractionsRepository = () => {
941
1224
  const providers = [];
@@ -996,12 +1279,12 @@ function createInteractionsProvider({
996
1279
  }
997
1280
 
998
1281
  // src/providers/document-elements-interactions-provider.ts
999
- var import_editor_elements3 = require("@elementor/editor-elements");
1000
- var import_editor_v1_adapters = require("@elementor/editor-v1-adapters");
1282
+ var import_editor_elements4 = require("@elementor/editor-elements");
1283
+ var import_editor_v1_adapters2 = require("@elementor/editor-v1-adapters");
1001
1284
  var ELEMENTS_INTERACTIONS_PROVIDER_KEY_PREFIX = "document-elements-interactions-";
1002
1285
  var documentElementsInteractionsProvider = createInteractionsProvider({
1003
1286
  key: () => {
1004
- const documentId = (0, import_editor_elements3.getCurrentDocumentId)();
1287
+ const documentId = (0, import_editor_elements4.getCurrentDocumentId)();
1005
1288
  if (!documentId) {
1006
1289
  const pendingKey = `${ELEMENTS_INTERACTIONS_PROVIDER_KEY_PREFIX}pending`;
1007
1290
  return pendingKey;
@@ -1011,20 +1294,20 @@ var documentElementsInteractionsProvider = createInteractionsProvider({
1011
1294
  },
1012
1295
  priority: 50,
1013
1296
  subscribe: (cb) => {
1014
- return (0, import_editor_v1_adapters.__privateListenTo)([(0, import_editor_v1_adapters.windowEvent)("elementor/element/update_interactions")], () => cb());
1297
+ return (0, import_editor_v1_adapters2.__privateListenTo)([(0, import_editor_v1_adapters2.windowEvent)("elementor/element/update_interactions")], () => cb());
1015
1298
  },
1016
1299
  actions: {
1017
1300
  all: () => {
1018
- const elements = (0, import_editor_elements3.getElements)();
1301
+ const elements = (0, import_editor_elements4.getElements)();
1019
1302
  const filtered = elements.filter((element) => {
1020
- const interactions = (0, import_editor_elements3.getElementInteractions)(element.id);
1303
+ const interactions = (0, import_editor_elements4.getElementInteractions)(element.id);
1021
1304
  if (!interactions) {
1022
1305
  return false;
1023
1306
  }
1024
1307
  return interactions?.items?.length > 0;
1025
1308
  });
1026
1309
  return filtered.map((element) => {
1027
- const interactions = (0, import_editor_elements3.getElementInteractions)(element.id);
1310
+ const interactions = (0, import_editor_elements4.getElementInteractions)(element.id);
1028
1311
  return {
1029
1312
  elementId: element.id,
1030
1313
  dataId: element.id,
@@ -1035,37 +1318,138 @@ var documentElementsInteractionsProvider = createInteractionsProvider({
1035
1318
  }
1036
1319
  });
1037
1320
 
1321
+ // src/init.ts
1322
+ var import_editor_mcp = require("@elementor/editor-mcp");
1323
+
1324
+ // src/commands/paste-interactions.ts
1325
+ var import_editor_elements5 = require("@elementor/editor-elements");
1326
+ var import_editor_v1_adapters3 = require("@elementor/editor-v1-adapters");
1327
+ var import_i18n6 = require("@wordpress/i18n");
1328
+
1329
+ // src/commands/get-clipboard-elements.ts
1330
+ function getClipboardElements(storageKey = "clipboard") {
1331
+ try {
1332
+ const storedData = JSON.parse(localStorage.getItem("elementor") ?? "{}");
1333
+ return storedData[storageKey]?.elements;
1334
+ } catch {
1335
+ return void 0;
1336
+ }
1337
+ }
1338
+
1339
+ // src/commands/paste-interactions.ts
1340
+ function isAtomicContainer(container) {
1341
+ const type = container?.model.get("widgetType") || container?.model.get("elType");
1342
+ const widgetsCache = (0, import_editor_elements5.getWidgetsCache)();
1343
+ const elementConfig = widgetsCache?.[type];
1344
+ return Boolean(elementConfig?.atomic_props_schema);
1345
+ }
1346
+ function getTitleForContainers(containers) {
1347
+ return containers.length > 1 ? (0, import_i18n6.__)("Elements", "elementor") : (0, import_editor_elements5.getElementLabel)(containers[0].id);
1348
+ }
1349
+ function normalizeClipboardInteractions(raw) {
1350
+ if (!raw) {
1351
+ return null;
1352
+ }
1353
+ const parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
1354
+ if (!parsed?.items?.length) {
1355
+ return null;
1356
+ }
1357
+ return { version: parsed.version ?? 1, items: parsed.items };
1358
+ }
1359
+ function regenerateInteractionIds(interactions) {
1360
+ const cloned = structuredClone(interactions);
1361
+ cloned.items?.forEach((item) => {
1362
+ if (item.$$type === "interaction-item" && item.value) {
1363
+ item.value.interaction_id = createString(generateTempInteractionId());
1364
+ }
1365
+ });
1366
+ return cloned;
1367
+ }
1368
+ function initPasteInteractionsCommand() {
1369
+ const undoablePasteInteractions = (0, import_editor_v1_adapters3.undoable)(
1370
+ {
1371
+ do: ({ containers, newInteractions }) => {
1372
+ const pasted = regenerateInteractionIds(newInteractions);
1373
+ return containers.map((container) => {
1374
+ const elementId = container.id;
1375
+ const previous = (0, import_editor_elements5.getElementInteractions)(elementId);
1376
+ (0, import_editor_elements5.updateElementInteractions)({
1377
+ elementId,
1378
+ interactions: pasted
1379
+ });
1380
+ return { elementId, previous: previous ?? { version: 1, items: [] } };
1381
+ });
1382
+ },
1383
+ undo: (_, revertData) => {
1384
+ revertData.forEach(({ elementId, previous }) => {
1385
+ (0, import_editor_elements5.updateElementInteractions)({
1386
+ elementId,
1387
+ interactions: previous.items?.length ? previous : void 0
1388
+ });
1389
+ });
1390
+ }
1391
+ },
1392
+ {
1393
+ title: ({ containers }) => getTitleForContainers(containers),
1394
+ subtitle: (0, import_i18n6.__)("Interactions Pasted", "elementor")
1395
+ }
1396
+ );
1397
+ (0, import_editor_v1_adapters3.__privateListenTo)((0, import_editor_v1_adapters3.commandStartEvent)("document/elements/paste-interactions"), (e) => {
1398
+ const args = e.args;
1399
+ const containers = args.containers ?? (args.container ? [args.container] : []);
1400
+ const storageKey = args.storageKey ?? "clipboard";
1401
+ if (!containers.length) {
1402
+ return;
1403
+ }
1404
+ const clipboardElements = getClipboardElements(storageKey);
1405
+ const [clipboardElement] = clipboardElements ?? [];
1406
+ if (!clipboardElement) {
1407
+ return;
1408
+ }
1409
+ const newInteractions = normalizeClipboardInteractions(clipboardElement.interactions);
1410
+ if (!newInteractions) {
1411
+ return;
1412
+ }
1413
+ const existingContainers = containers.filter((c) => (0, import_editor_elements5.getContainer)(c.id));
1414
+ const validContainers = existingContainers.filter(isAtomicContainer);
1415
+ if (!validContainers.length) {
1416
+ return;
1417
+ }
1418
+ undoablePasteInteractions({ containers: validContainers, newInteractions });
1419
+ });
1420
+ }
1421
+
1038
1422
  // src/components/controls/direction.tsx
1039
1423
  var React12 = __toESM(require("react"));
1040
- var import_react10 = require("react");
1424
+ var import_react11 = require("react");
1041
1425
  var import_editor_controls6 = require("@elementor/editor-controls");
1042
1426
  var import_icons3 = require("@elementor/icons");
1043
- var import_i18n6 = require("@wordpress/i18n");
1427
+ var import_i18n7 = require("@wordpress/i18n");
1044
1428
  function Direction({ value, onChange, interactionType }) {
1045
- const options = (0, import_react10.useMemo)(() => {
1429
+ const options = (0, import_react11.useMemo)(() => {
1046
1430
  const isIn = interactionType === "in";
1047
1431
  return [
1048
1432
  {
1049
1433
  value: "top",
1050
- label: isIn ? (0, import_i18n6.__)("From top", "elementor") : (0, import_i18n6.__)("To top", "elementor"),
1434
+ label: isIn ? (0, import_i18n7.__)("From top", "elementor") : (0, import_i18n7.__)("To top", "elementor"),
1051
1435
  renderContent: ({ size }) => isIn ? /* @__PURE__ */ React12.createElement(import_icons3.ArrowDownSmallIcon, { fontSize: size }) : /* @__PURE__ */ React12.createElement(import_icons3.ArrowUpSmallIcon, { fontSize: size }),
1052
1436
  showTooltip: true
1053
1437
  },
1054
1438
  {
1055
1439
  value: "bottom",
1056
- label: interactionType === "in" ? (0, import_i18n6.__)("From bottom", "elementor") : (0, import_i18n6.__)("To bottom", "elementor"),
1440
+ label: interactionType === "in" ? (0, import_i18n7.__)("From bottom", "elementor") : (0, import_i18n7.__)("To bottom", "elementor"),
1057
1441
  renderContent: ({ size }) => isIn ? /* @__PURE__ */ React12.createElement(import_icons3.ArrowUpSmallIcon, { fontSize: size }) : /* @__PURE__ */ React12.createElement(import_icons3.ArrowDownSmallIcon, { fontSize: size }),
1058
1442
  showTooltip: true
1059
1443
  },
1060
1444
  {
1061
1445
  value: "left",
1062
- label: interactionType === "in" ? (0, import_i18n6.__)("From left", "elementor") : (0, import_i18n6.__)("To left", "elementor"),
1446
+ label: interactionType === "in" ? (0, import_i18n7.__)("From left", "elementor") : (0, import_i18n7.__)("To left", "elementor"),
1063
1447
  renderContent: ({ size }) => isIn ? /* @__PURE__ */ React12.createElement(import_icons3.ArrowRightIcon, { fontSize: size }) : /* @__PURE__ */ React12.createElement(import_icons3.ArrowLeftIcon, { fontSize: size }),
1064
1448
  showTooltip: true
1065
1449
  },
1066
1450
  {
1067
1451
  value: "right",
1068
- label: interactionType === "in" ? (0, import_i18n6.__)("From right", "elementor") : (0, import_i18n6.__)("To right", "elementor"),
1452
+ label: interactionType === "in" ? (0, import_i18n7.__)("From right", "elementor") : (0, import_i18n7.__)("To right", "elementor"),
1069
1453
  renderContent: ({ size }) => isIn ? /* @__PURE__ */ React12.createElement(import_icons3.ArrowLeftIcon, { fontSize: size }) : /* @__PURE__ */ React12.createElement(import_icons3.ArrowRightIcon, { fontSize: size }),
1070
1454
  showTooltip: true
1071
1455
  }
@@ -1076,27 +1460,35 @@ function Direction({ value, onChange, interactionType }) {
1076
1460
 
1077
1461
  // src/components/controls/easing.tsx
1078
1462
  var React15 = __toESM(require("react"));
1079
- var import_i18n9 = require("@wordpress/i18n");
1463
+ var import_i18n10 = require("@wordpress/i18n");
1080
1464
 
1081
1465
  // src/ui/promotion-select.tsx
1082
1466
  var React14 = __toESM(require("react"));
1083
- var import_react12 = require("react");
1467
+ var import_react13 = require("react");
1084
1468
  var import_editor_ui2 = require("@elementor/editor-ui");
1085
1469
  var import_ui9 = require("@elementor/ui");
1086
- var import_i18n8 = require("@wordpress/i18n");
1470
+ var import_i18n9 = require("@wordpress/i18n");
1087
1471
 
1088
1472
  // src/ui/interactions-promotion-chip.tsx
1089
1473
  var React13 = __toESM(require("react"));
1090
- var import_react11 = require("react");
1474
+ var import_react12 = require("react");
1475
+ var import_editor_controls7 = require("@elementor/editor-controls");
1091
1476
  var import_editor_ui = require("@elementor/editor-ui");
1092
1477
  var import_ui8 = require("@elementor/ui");
1093
- var import_i18n7 = require("@wordpress/i18n");
1094
- var InteractionsPromotionChip = (0, import_react11.forwardRef)(
1095
- ({ content, upgradeUrl, anchorRef }, ref) => {
1096
- const [isOpen, setIsOpen] = (0, import_react11.useState)(false);
1478
+ var import_i18n8 = require("@wordpress/i18n");
1479
+ var InteractionsPromotionChip = (0, import_react12.forwardRef)(
1480
+ ({ content, upgradeUrl, anchorRef, trackingData }, ref) => {
1481
+ const [isOpen, setIsOpen] = (0, import_react12.useState)(false);
1097
1482
  (0, import_editor_ui.useCanvasClickHandler)(isOpen, () => setIsOpen(false));
1098
- const toggle = () => setIsOpen((prev) => !prev);
1099
- (0, import_react11.useImperativeHandle)(ref, () => ({ toggle }), []);
1483
+ const toggle = (0, import_react12.useCallback)(() => {
1484
+ setIsOpen((prev) => {
1485
+ if (!prev) {
1486
+ (0, import_editor_controls7.trackViewPromotion)(trackingData);
1487
+ }
1488
+ return !prev;
1489
+ });
1490
+ }, [trackingData]);
1491
+ (0, import_react12.useImperativeHandle)(ref, () => ({ toggle }), [toggle]);
1100
1492
  const handleToggle = (e) => {
1101
1493
  e.stopPropagation();
1102
1494
  toggle();
@@ -1105,16 +1497,17 @@ var InteractionsPromotionChip = (0, import_react11.forwardRef)(
1105
1497
  import_editor_ui.PromotionPopover,
1106
1498
  {
1107
1499
  open: isOpen,
1108
- title: (0, import_i18n7.__)("Interactions", "elementor"),
1500
+ title: (0, import_i18n8.__)("Interactions", "elementor"),
1109
1501
  content,
1110
- ctaText: (0, import_i18n7.__)("Upgrade now", "elementor"),
1502
+ ctaText: (0, import_i18n8.__)("Upgrade now", "elementor"),
1111
1503
  ctaUrl: upgradeUrl,
1112
1504
  anchorRef,
1113
1505
  placement: anchorRef ? "right-start" : void 0,
1114
1506
  onClose: (e) => {
1115
1507
  e.stopPropagation();
1116
1508
  setIsOpen(false);
1117
- }
1509
+ },
1510
+ onCtaClick: () => (0, import_editor_controls7.trackUpgradePromotionClick)(trackingData)
1118
1511
  },
1119
1512
  /* @__PURE__ */ React13.createElement(
1120
1513
  import_ui8.Box,
@@ -1128,7 +1521,6 @@ var InteractionsPromotionChip = (0, import_react11.forwardRef)(
1128
1521
  );
1129
1522
  }
1130
1523
  );
1131
- InteractionsPromotionChip.displayName = "InteractionsPromotionChip";
1132
1524
 
1133
1525
  // src/ui/promotion-select.tsx
1134
1526
  function PromotionSelect({
@@ -1138,10 +1530,11 @@ function PromotionSelect({
1138
1530
  disabledOptions,
1139
1531
  promotionLabel,
1140
1532
  promotionContent,
1141
- upgradeUrl
1533
+ upgradeUrl,
1534
+ trackingData
1142
1535
  }) {
1143
- const promotionRef = (0, import_react12.useRef)(null);
1144
- const anchorRef = (0, import_react12.useRef)(null);
1536
+ const promotionRef = (0, import_react13.useRef)(null);
1537
+ const anchorRef = (0, import_react13.useRef)(null);
1145
1538
  return /* @__PURE__ */ React14.createElement(
1146
1539
  import_ui9.Select,
1147
1540
  {
@@ -1169,14 +1562,15 @@ function PromotionSelect({
1169
1562
  promotionRef.current?.toggle();
1170
1563
  }
1171
1564
  },
1172
- promotionLabel ?? (0, import_i18n8.__)("PRO features", "elementor"),
1565
+ promotionLabel ?? (0, import_i18n9.__)("PRO features", "elementor"),
1173
1566
  /* @__PURE__ */ React14.createElement(
1174
1567
  InteractionsPromotionChip,
1175
1568
  {
1176
1569
  content: promotionContent,
1177
1570
  upgradeUrl,
1178
1571
  ref: promotionRef,
1179
- anchorRef
1572
+ anchorRef,
1573
+ trackingData
1180
1574
  }
1181
1575
  )
1182
1576
  ),
@@ -1185,14 +1579,15 @@ function PromotionSelect({
1185
1579
  }
1186
1580
 
1187
1581
  // src/components/controls/easing.tsx
1582
+ var TRACKING_DATA = { target_name: "interactions_easing", location_l2: "interactions" };
1188
1583
  var EASING_OPTIONS = {
1189
- easeIn: (0, import_i18n9.__)("Ease In", "elementor"),
1190
- easeInOut: (0, import_i18n9.__)("Ease In Out", "elementor"),
1191
- easeOut: (0, import_i18n9.__)("Ease Out", "elementor"),
1192
- backIn: (0, import_i18n9.__)("Back In", "elementor"),
1193
- backInOut: (0, import_i18n9.__)("Back In Out", "elementor"),
1194
- backOut: (0, import_i18n9.__)("Back Out", "elementor"),
1195
- linear: (0, import_i18n9.__)("Linear", "elementor")
1584
+ easeIn: (0, import_i18n10.__)("Ease In", "elementor"),
1585
+ easeInOut: (0, import_i18n10.__)("Ease In Out", "elementor"),
1586
+ easeOut: (0, import_i18n10.__)("Ease Out", "elementor"),
1587
+ backIn: (0, import_i18n10.__)("Back In", "elementor"),
1588
+ backInOut: (0, import_i18n10.__)("Back In Out", "elementor"),
1589
+ backOut: (0, import_i18n10.__)("Back Out", "elementor"),
1590
+ linear: (0, import_i18n10.__)("Linear", "elementor")
1196
1591
  };
1197
1592
  var BASE_EASINGS = ["easeIn"];
1198
1593
  function Easing({}) {
@@ -1208,20 +1603,22 @@ function Easing({}) {
1208
1603
  value: DEFAULT_VALUES.easing,
1209
1604
  baseOptions,
1210
1605
  disabledOptions,
1211
- promotionContent: (0, import_i18n9.__)("Upgrade to control the smoothness of the interaction.", "elementor"),
1212
- upgradeUrl: "https://go.elementor.com/go-pro-interactions-easing-modal/"
1606
+ promotionContent: (0, import_i18n10.__)("Upgrade to control the smoothness of the interaction.", "elementor"),
1607
+ upgradeUrl: "https://go.elementor.com/go-pro-interactions-easing-modal/",
1608
+ trackingData: TRACKING_DATA
1213
1609
  }
1214
1610
  );
1215
1611
  }
1216
1612
 
1217
1613
  // src/components/controls/effect.tsx
1218
1614
  var React16 = __toESM(require("react"));
1219
- var import_i18n10 = require("@wordpress/i18n");
1615
+ var import_i18n11 = require("@wordpress/i18n");
1616
+ var TRACKING_DATA2 = { target_name: "interactions_effect", location_l2: "interactions" };
1220
1617
  var EFFECT_OPTIONS = {
1221
- fade: (0, import_i18n10.__)("Fade", "elementor"),
1222
- slide: (0, import_i18n10.__)("Slide", "elementor"),
1223
- scale: (0, import_i18n10.__)("Scale", "elementor"),
1224
- custom: (0, import_i18n10.__)("Custom", "elementor")
1618
+ fade: (0, import_i18n11.__)("Fade", "elementor"),
1619
+ slide: (0, import_i18n11.__)("Slide", "elementor"),
1620
+ scale: (0, import_i18n11.__)("Scale", "elementor"),
1621
+ custom: (0, import_i18n11.__)("Custom", "elementor")
1225
1622
  };
1226
1623
  var BASE_EFFECTS = ["fade", "slide", "scale"];
1227
1624
  function Effect({ value, onChange }) {
@@ -1238,87 +1635,161 @@ function Effect({ value, onChange }) {
1238
1635
  onChange,
1239
1636
  baseOptions,
1240
1637
  disabledOptions,
1241
- promotionLabel: (0, import_i18n10.__)("PRO effects", "elementor"),
1242
- promotionContent: (0, import_i18n10.__)(
1638
+ promotionLabel: (0, import_i18n11.__)("PRO effects", "elementor"),
1639
+ promotionContent: (0, import_i18n11.__)(
1243
1640
  "Upgrade to further customize your animation with opacity, scale, move, rotate and more.",
1244
1641
  "elementor"
1245
1642
  ),
1246
- upgradeUrl: "https://go.elementor.com/go-pro-interactions-custom-effect-modal/"
1643
+ upgradeUrl: "https://go.elementor.com/go-pro-interactions-custom-effect-modal/",
1644
+ trackingData: TRACKING_DATA2
1247
1645
  }
1248
1646
  );
1249
1647
  }
1250
1648
 
1251
1649
  // src/components/controls/effect-type.tsx
1252
1650
  var React17 = __toESM(require("react"));
1253
- var import_editor_controls7 = require("@elementor/editor-controls");
1254
- var import_i18n11 = require("@wordpress/i18n");
1651
+ var import_editor_controls8 = require("@elementor/editor-controls");
1652
+ var import_i18n12 = require("@wordpress/i18n");
1255
1653
  function EffectType({ value, onChange }) {
1256
1654
  const options = [
1257
1655
  {
1258
1656
  value: "in",
1259
- label: (0, import_i18n11.__)("In", "elementor"),
1260
- renderContent: () => (0, import_i18n11.__)("In", "elementor"),
1657
+ label: (0, import_i18n12.__)("In", "elementor"),
1658
+ renderContent: () => (0, import_i18n12.__)("In", "elementor"),
1261
1659
  showTooltip: true
1262
1660
  },
1263
1661
  {
1264
1662
  value: "out",
1265
- label: (0, import_i18n11.__)("Out", "elementor"),
1266
- renderContent: () => (0, import_i18n11.__)("Out", "elementor"),
1663
+ label: (0, import_i18n12.__)("Out", "elementor"),
1664
+ renderContent: () => (0, import_i18n12.__)("Out", "elementor"),
1267
1665
  showTooltip: true
1268
1666
  }
1269
1667
  ];
1270
- return /* @__PURE__ */ React17.createElement(import_editor_controls7.ToggleButtonGroupUi, { items: options, exclusive: true, onChange, value });
1668
+ return /* @__PURE__ */ React17.createElement(import_editor_controls8.ToggleButtonGroupUi, { items: options, exclusive: true, onChange, value });
1271
1669
  }
1272
1670
 
1273
- // src/components/controls/replay.tsx
1274
- var React18 = __toESM(require("react"));
1275
- var import_editor_controls8 = require("@elementor/editor-controls");
1671
+ // src/components/controls/repeat.tsx
1672
+ var React19 = __toESM(require("react"));
1673
+ var import_react15 = require("react");
1674
+ var import_editor_controls9 = require("@elementor/editor-controls");
1276
1675
  var import_icons4 = require("@elementor/icons");
1676
+ var import_i18n13 = require("@wordpress/i18n");
1677
+
1678
+ // src/ui/promotion-overlay-layout.tsx
1679
+ var React18 = __toESM(require("react"));
1680
+ var import_react14 = require("react");
1277
1681
  var import_ui10 = require("@elementor/ui");
1278
- var import_i18n12 = require("@wordpress/i18n");
1682
+ var OVERLAY_GRID = "1 / 1";
1683
+ var CHIP_OFFSET = "50%";
1684
+ var PromotionOverlayLayout = (0, import_react14.forwardRef)(
1685
+ ({ children, promotionChip }, ref) => /* @__PURE__ */ React18.createElement(import_ui10.Box, { ref, sx: { display: "grid", alignItems: "center" } }, /* @__PURE__ */ React18.createElement(import_ui10.Box, { sx: { gridArea: OVERLAY_GRID } }, children), /* @__PURE__ */ React18.createElement(import_ui10.Box, { sx: { gridArea: OVERLAY_GRID, marginInlineEnd: CHIP_OFFSET, justifySelf: "end" } }, promotionChip))
1686
+ );
1687
+
1688
+ // src/components/controls/repeat.tsx
1689
+ var TRACKING_DATA3 = { target_name: "interactions_repeat", location_l2: "interactions" };
1690
+ var REPEAT_OPTIONS = {
1691
+ times: (0, import_i18n13.__)("times", "elementor"),
1692
+ loop: (0, import_i18n13.__)("loop", "elementor")
1693
+ };
1694
+ var REPEAT_TOOLTIPS = {
1695
+ times: (0, import_i18n13.__)("Enable number", "elementor"),
1696
+ loop: (0, import_i18n13.__)("Infinite repeat", "elementor")
1697
+ };
1698
+ function Repeat() {
1699
+ const repeatContainerRef = (0, import_react15.useRef)(null);
1700
+ const options = [
1701
+ {
1702
+ value: REPEAT_OPTIONS.times,
1703
+ disabled: true,
1704
+ label: REPEAT_TOOLTIPS.times,
1705
+ renderContent: ({ size }) => /* @__PURE__ */ React19.createElement(import_icons4.Number123Icon, { fontSize: size }),
1706
+ showTooltip: true
1707
+ },
1708
+ {
1709
+ value: REPEAT_OPTIONS.loop,
1710
+ disabled: true,
1711
+ label: REPEAT_TOOLTIPS.loop,
1712
+ renderContent: ({ size }) => /* @__PURE__ */ React19.createElement(import_icons4.RepeatIcon, { fontSize: size }),
1713
+ showTooltip: true
1714
+ }
1715
+ ];
1716
+ return /* @__PURE__ */ React19.createElement(
1717
+ PromotionOverlayLayout,
1718
+ {
1719
+ ref: repeatContainerRef,
1720
+ promotionChip: /* @__PURE__ */ React19.createElement(
1721
+ InteractionsPromotionChip,
1722
+ {
1723
+ content: (0, import_i18n13.__)("Upgrade to control how many times the animation repeats.", "elementor"),
1724
+ upgradeUrl: "https://go.elementor.com/go-pro-interactions-repeat-modal/",
1725
+ anchorRef: repeatContainerRef,
1726
+ trackingData: TRACKING_DATA3
1727
+ }
1728
+ )
1729
+ },
1730
+ /* @__PURE__ */ React19.createElement(import_editor_controls9.ToggleButtonGroupUi, { items: options, exclusive: true, onChange: () => {
1731
+ }, value: "" })
1732
+ );
1733
+ }
1734
+
1735
+ // src/components/controls/replay.tsx
1736
+ var React20 = __toESM(require("react"));
1737
+ var import_react16 = require("react");
1738
+ var import_editor_controls10 = require("@elementor/editor-controls");
1739
+ var import_icons5 = require("@elementor/icons");
1740
+ var import_i18n14 = require("@wordpress/i18n");
1741
+ var TRACKING_DATA4 = { target_name: "interactions_replay", location_l2: "interactions" };
1279
1742
  var REPLAY_OPTIONS = {
1280
- no: (0, import_i18n12.__)("No", "elementor"),
1281
- yes: (0, import_i18n12.__)("Yes", "elementor")
1743
+ no: (0, import_i18n14.__)("No", "elementor"),
1744
+ yes: (0, import_i18n14.__)("Yes", "elementor")
1282
1745
  };
1283
1746
  var BASE_REPLAY = ["no"];
1284
- var OVERLAY_GRID = "1 / 1";
1285
- var CHIP_OFFSET = "50%";
1286
- function Replay({ onChange, anchorRef }) {
1747
+ function Replay({ onChange }) {
1748
+ const replayContainerRef = (0, import_react16.useRef)(null);
1287
1749
  const options = [
1288
1750
  {
1289
1751
  value: false,
1290
1752
  disabled: false,
1291
1753
  label: REPLAY_OPTIONS.no,
1292
- renderContent: ({ size }) => /* @__PURE__ */ React18.createElement(import_icons4.MinusIcon, { fontSize: size }),
1754
+ renderContent: ({ size }) => /* @__PURE__ */ React20.createElement(import_icons5.MinusIcon, { fontSize: size }),
1293
1755
  showTooltip: true
1294
1756
  },
1295
1757
  {
1296
1758
  value: true,
1297
1759
  disabled: true,
1298
1760
  label: REPLAY_OPTIONS.yes,
1299
- renderContent: ({ size }) => /* @__PURE__ */ React18.createElement(import_icons4.CheckIcon, { fontSize: size }),
1761
+ renderContent: ({ size }) => /* @__PURE__ */ React20.createElement(import_icons5.CheckIcon, { fontSize: size }),
1300
1762
  showTooltip: true
1301
1763
  }
1302
1764
  ];
1303
- return /* @__PURE__ */ React18.createElement(import_ui10.Box, { sx: { display: "grid", alignItems: "center" } }, /* @__PURE__ */ React18.createElement(import_ui10.Box, { sx: { gridArea: OVERLAY_GRID } }, /* @__PURE__ */ React18.createElement(import_editor_controls8.ToggleButtonGroupUi, { items: options, exclusive: true, onChange, value: false })), /* @__PURE__ */ React18.createElement(import_ui10.Box, { sx: { gridArea: OVERLAY_GRID, marginInlineEnd: CHIP_OFFSET, justifySelf: "end" } }, /* @__PURE__ */ React18.createElement(
1304
- InteractionsPromotionChip,
1765
+ return /* @__PURE__ */ React20.createElement(
1766
+ PromotionOverlayLayout,
1305
1767
  {
1306
- content: (0, import_i18n12.__)("Upgrade to run the animation every time its trigger occurs.", "elementor"),
1307
- upgradeUrl: "https://go.elementor.com/go-pro-interactions-replay-modal/",
1308
- anchorRef
1309
- }
1310
- )));
1768
+ ref: replayContainerRef,
1769
+ promotionChip: /* @__PURE__ */ React20.createElement(
1770
+ InteractionsPromotionChip,
1771
+ {
1772
+ content: (0, import_i18n14.__)("Upgrade to run the animation every time its trigger occurs.", "elementor"),
1773
+ upgradeUrl: "https://go.elementor.com/go-pro-interactions-replay-modal/",
1774
+ anchorRef: replayContainerRef,
1775
+ trackingData: TRACKING_DATA4
1776
+ }
1777
+ )
1778
+ },
1779
+ /* @__PURE__ */ React20.createElement(import_editor_controls10.ToggleButtonGroupUi, { items: options, exclusive: true, onChange, value: false })
1780
+ );
1311
1781
  }
1312
1782
 
1313
1783
  // src/components/controls/trigger.tsx
1314
- var React19 = __toESM(require("react"));
1315
- var import_i18n13 = require("@wordpress/i18n");
1784
+ var React21 = __toESM(require("react"));
1785
+ var import_i18n15 = require("@wordpress/i18n");
1786
+ var TRACKING_DATA5 = { target_name: "interactions_trigger", location_l2: "interactions" };
1316
1787
  var TRIGGER_OPTIONS = {
1317
- load: (0, import_i18n13.__)("Page load", "elementor"),
1318
- scrollIn: (0, import_i18n13.__)("Scroll into view", "elementor"),
1319
- scrollOn: (0, import_i18n13.__)("While scrolling", "elementor"),
1320
- hover: (0, import_i18n13.__)("On hover", "elementor"),
1321
- click: (0, import_i18n13.__)("On click", "elementor")
1788
+ load: (0, import_i18n15.__)("Page load", "elementor"),
1789
+ scrollIn: (0, import_i18n15.__)("Scroll into view", "elementor"),
1790
+ scrollOn: (0, import_i18n15.__)("While scrolling", "elementor"),
1791
+ hover: (0, import_i18n15.__)("On hover", "elementor"),
1792
+ click: (0, import_i18n15.__)("On click", "elementor")
1322
1793
  };
1323
1794
  var BASE_TRIGGERS = ["load", "scrollIn"];
1324
1795
  function Trigger({ value, onChange }) {
@@ -1328,25 +1799,26 @@ function Trigger({ value, onChange }) {
1328
1799
  const disabledOptions = Object.fromEntries(
1329
1800
  Object.entries(TRIGGER_OPTIONS).filter(([key]) => !BASE_TRIGGERS.includes(key))
1330
1801
  );
1331
- return /* @__PURE__ */ React19.createElement(
1802
+ return /* @__PURE__ */ React21.createElement(
1332
1803
  PromotionSelect,
1333
1804
  {
1334
1805
  value: value in baseOptions ? value : DEFAULT_VALUES.trigger,
1335
1806
  onChange,
1336
1807
  baseOptions,
1337
1808
  disabledOptions,
1338
- promotionLabel: (0, import_i18n13.__)("PRO triggers", "elementor"),
1339
- promotionContent: (0, import_i18n13.__)("Upgrade to unlock more interactions triggers.", "elementor"),
1340
- upgradeUrl: "https://go.elementor.com/go-pro-interactions-triggers-modal/"
1809
+ promotionLabel: (0, import_i18n15.__)("PRO triggers", "elementor"),
1810
+ promotionContent: (0, import_i18n15.__)("Upgrade to unlock more interactions triggers.", "elementor"),
1811
+ upgradeUrl: "https://go.elementor.com/go-pro-interactions-triggers-modal/",
1812
+ trackingData: TRACKING_DATA5
1341
1813
  }
1342
1814
  );
1343
1815
  }
1344
1816
 
1345
1817
  // src/hooks/on-duplicate.ts
1346
- var import_editor_elements4 = require("@elementor/editor-elements");
1347
- var import_editor_v1_adapters2 = require("@elementor/editor-v1-adapters");
1818
+ var import_editor_elements6 = require("@elementor/editor-elements");
1819
+ var import_editor_v1_adapters4 = require("@elementor/editor-v1-adapters");
1348
1820
  function initCleanInteractionIdsOnDuplicate() {
1349
- (0, import_editor_v1_adapters2.registerDataHook)("after", "document/elements/duplicate", (_args, result) => {
1821
+ (0, import_editor_v1_adapters4.registerDataHook)("after", "document/elements/duplicate", (_args, result) => {
1350
1822
  const containers = Array.isArray(result) ? result : [result];
1351
1823
  containers.forEach((container) => {
1352
1824
  cleanInteractionIdsRecursive(container.id);
@@ -1354,16 +1826,16 @@ function initCleanInteractionIdsOnDuplicate() {
1354
1826
  });
1355
1827
  }
1356
1828
  function cleanInteractionIdsRecursive(elementId) {
1357
- const container = (0, import_editor_elements4.getContainer)(elementId);
1829
+ const container = (0, import_editor_elements6.getContainer)(elementId);
1358
1830
  if (!container) {
1359
1831
  return;
1360
1832
  }
1361
- (0, import_editor_elements4.getAllDescendants)(container).forEach((element) => {
1833
+ (0, import_editor_elements6.getAllDescendants)(container).forEach((element) => {
1362
1834
  cleanInteractionIds(element.id);
1363
1835
  });
1364
1836
  }
1365
1837
  function cleanInteractionIds(elementId) {
1366
- const container = (0, import_editor_elements4.getContainer)(elementId);
1838
+ const container = (0, import_editor_elements6.getContainer)(elementId);
1367
1839
  if (!container) {
1368
1840
  return;
1369
1841
  }
@@ -1380,12 +1852,6 @@ function cleanInteractionIds(elementId) {
1380
1852
  container.model.set("interactions", updatedInteractions);
1381
1853
  }
1382
1854
 
1383
- // src/mcp/index.ts
1384
- var import_editor_mcp = require("@elementor/editor-mcp");
1385
-
1386
- // src/mcp/constants.ts
1387
- var MAX_INTERACTIONS_PER_ELEMENT = 5;
1388
-
1389
1855
  // src/mcp/resources/interactions-schema-resource.ts
1390
1856
  var import_utils = require("@elementor/utils");
1391
1857
 
@@ -1406,7 +1872,7 @@ var baseSchema = {
1406
1872
  var proSchema = {
1407
1873
  trigger: import_schema.z.enum(["load", "scrollIn", "scrollOut", "scrollOn", "hover", "click"]).optional().describe("Event that triggers the animation"),
1408
1874
  effect: import_schema.z.enum(["fade", "slide", "scale", "custom"]).optional().describe("Animation effect type"),
1409
- customEffect: import_schema.z.object({
1875
+ customEffects: import_schema.z.object({
1410
1876
  keyframes: import_schema.z.array(
1411
1877
  import_schema.z.object({
1412
1878
  stop: import_schema.z.number().describe("The stop of the keyframe in percent, can be either 0 or 100"),
@@ -1462,13 +1928,77 @@ var initInteractionsSchemaResource = (reg) => {
1462
1928
  };
1463
1929
 
1464
1930
  // src/mcp/tools/manage-element-interaction-tool.ts
1465
- var import_editor_elements5 = require("@elementor/editor-elements");
1931
+ var import_editor_elements7 = require("@elementor/editor-elements");
1466
1932
  var import_schema3 = require("@elementor/schema");
1467
1933
  var import_utils2 = require("@elementor/utils");
1934
+
1935
+ // src/mcp/constants.ts
1936
+ var MAX_INTERACTIONS_PER_ELEMENT = 5;
1937
+ var EDITOR_INTERACTIONS_MCP_INSTRUCTIONS = `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.
1938
+ ** IMPORTANT **
1939
+ Use the "interactions-schema" resource to get the schema of the interactions.
1940
+ Actions:
1941
+ - get: Read the current interactions on the element.
1942
+ - add: Add a new interaction (max ${MAX_INTERACTIONS_PER_ELEMENT} per element).
1943
+ - update: Update an existing interaction by its interactionId.
1944
+ - delete: Remove a specific interaction by its interactionId.
1945
+ - clear: Remove all interactions from the element.
1946
+
1947
+ For add/update, provide: trigger, effect, effectType, direction (required for slide effect), duration, delay, easing.
1948
+ Use excludedBreakpoints to disable the animation on specific responsive breakpoints (e.g. ["mobile", "tablet"]).
1949
+ Example Get Request:
1950
+ {
1951
+ "elementId": "123",
1952
+ "action": "get",
1953
+ "interactionId": "123",
1954
+ "animationData": {
1955
+ "trigger": "click",
1956
+ "effect": "fade",
1957
+ }
1958
+ }
1959
+ Example Add Request:
1960
+ {
1961
+ "elementId": "123",
1962
+ "action": "add",
1963
+ "animationData": {
1964
+ "effectType": "in",
1965
+ "direction": "top",
1966
+ "trigger": "click",
1967
+ "effect": "fade",
1968
+ "duration": 1000,
1969
+ "delay": 0,
1970
+ "easing": "easeIn",
1971
+ "excludedBreakpoints": ["mobile", "tablet"],
1972
+ }
1973
+ }
1974
+ Example Update Request:
1975
+ {
1976
+ "elementId": "123",
1977
+ "action": "update",
1978
+ "interactionId": "123",
1979
+ "animationData": {
1980
+ "trigger": "click",
1981
+ "effect": "fade",
1982
+ }
1983
+ }
1984
+ Example Delete Request:
1985
+ {
1986
+ "elementId": "123",
1987
+ "action": "delete",
1988
+ "interactionId": "123",
1989
+ }
1990
+ Example Clear Request:
1991
+ {
1992
+ "elementId": "123",
1993
+ "action": "clear",
1994
+ }`;
1995
+
1996
+ // src/mcp/tools/manage-element-interaction-tool.ts
1468
1997
  var EMPTY_INTERACTIONS = {
1469
1998
  version: 1,
1470
1999
  items: []
1471
2000
  };
2001
+ var EFFECTS_WITHOUT_TYPE = ["custom"];
1472
2002
  var initManageElementInteractionTool = (reg) => {
1473
2003
  const { addTool } = reg;
1474
2004
  const extendedSchema = (0, import_utils2.isProActive)() ? { ...baseSchema, ...proSchema } : baseSchema;
@@ -1495,16 +2025,36 @@ var initManageElementInteractionTool = (reg) => {
1495
2025
  },
1496
2026
  handler: (input) => {
1497
2027
  const { elementId, action, interactionId, ...animationData } = input;
2028
+ const { effectType, ...restAnimationData } = animationData;
2029
+ const effect = restAnimationData.effect;
2030
+ const resolvedType = effectType ?? (effect && !EFFECTS_WITHOUT_TYPE.includes(effect) ? "in" : void 0);
1498
2031
  const allInteractions = interactionsRepository.all();
1499
2032
  const elementData = allInteractions.find((data) => data.elementId === elementId);
1500
2033
  const currentInteractions = elementData?.interactions ?? EMPTY_INTERACTIONS;
1501
2034
  if (action === "get") {
2035
+ const summary = currentInteractions.items.map((item) => {
2036
+ const { value } = item;
2037
+ const animValue = value.animation.value;
2038
+ const timingValue = animValue.timing_config.value;
2039
+ const configValue = animValue.config.value;
2040
+ return {
2041
+ id: extractString(value.interaction_id),
2042
+ trigger: extractString(value.trigger),
2043
+ effect: extractString(animValue.effect),
2044
+ effectType: extractString(animValue.type),
2045
+ direction: extractString(animValue.direction),
2046
+ duration: extractSize(timingValue.duration),
2047
+ delay: extractSize(timingValue.delay),
2048
+ easing: extractString(configValue.easing),
2049
+ excludedBreakpoints: extractExcludedBreakpoints(value.breakpoints)
2050
+ };
2051
+ });
1502
2052
  return {
1503
2053
  success: true,
1504
2054
  elementId,
1505
2055
  action,
1506
- interactions: currentInteractions.items,
1507
- count: currentInteractions.items.length
2056
+ interactions: summary,
2057
+ count: summary.length
1508
2058
  };
1509
2059
  }
1510
2060
  let updatedItems = [...currentInteractions.items];
@@ -1517,7 +2067,8 @@ var initManageElementInteractionTool = (reg) => {
1517
2067
  }
1518
2068
  const newItem = createInteractionItem({
1519
2069
  interactionId: generateTempInteractionId(),
1520
- ...animationData
2070
+ ...restAnimationData,
2071
+ type: resolvedType
1521
2072
  });
1522
2073
  updatedItems = [...updatedItems, newItem];
1523
2074
  break;
@@ -1536,7 +2087,8 @@ var initManageElementInteractionTool = (reg) => {
1536
2087
  }
1537
2088
  const updatedItem = createInteractionItem({
1538
2089
  interactionId,
1539
- ...animationData
2090
+ ...restAnimationData,
2091
+ type: resolvedType
1540
2092
  });
1541
2093
  updatedItems = [
1542
2094
  ...updatedItems.slice(0, itemIndex),
@@ -1570,7 +2122,7 @@ var initManageElementInteractionTool = (reg) => {
1570
2122
  items: updatedItems
1571
2123
  };
1572
2124
  try {
1573
- (0, import_editor_elements5.updateElementInteractions)({ elementId, interactions: updatedInteractions });
2125
+ (0, import_editor_elements7.updateElementInteractions)({ elementId, interactions: updatedInteractions });
1574
2126
  } catch (error) {
1575
2127
  throw new Error(
1576
2128
  `Failed to update interactions for element "${elementId}": ${error instanceof Error ? error.message : "Unknown error"}`
@@ -1587,73 +2139,18 @@ var initManageElementInteractionTool = (reg) => {
1587
2139
  };
1588
2140
 
1589
2141
  // src/mcp/index.ts
1590
- var initMcpInteractions = () => {
1591
- const reg = (0, import_editor_mcp.getMCPByDomain)("interactions", {
1592
- instructions: `
1593
- 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.
1594
- ** IMPORTANT **
1595
- Use the "interactions-schema" resource to get the schema of the interactions.
1596
- Actions:
1597
- - get: Read the current interactions on the element.
1598
- - add: Add a new interaction (max ${MAX_INTERACTIONS_PER_ELEMENT} per element).
1599
- - update: Update an existing interaction by its interactionId.
1600
- - delete: Remove a specific interaction by its interactionId.
1601
- - clear: Remove all interactions from the element.
1602
-
1603
- For add/update, provide: trigger, effect, effectType, direction (required for slide effect), duration, delay, easing.
1604
- Use excludedBreakpoints to disable the animation on specific responsive breakpoints (e.g. ["mobile", "tablet"]).
1605
- Example Get Request:
1606
- {
1607
- "elementId": "123",
1608
- "action": "get",
1609
- "interactionId": "123",
1610
- "animationData": {
1611
- "trigger": "click",
1612
- "effect": "fade",
1613
- }
1614
- }
1615
- Example Add Request:
1616
- {
1617
- "elementId": "123",
1618
- "action": "add",
1619
- "animationData": {
1620
- "effectType": "in",
1621
- "direction": "top",
1622
- "trigger": "click",
1623
- "effect": "fade",
1624
- "duration": 1000,
1625
- "delay": 0,
1626
- "easing": "easeIn",
1627
- "excludedBreakpoints": ["mobile", "tablet"],
1628
- }
1629
- }
1630
- Example Update Request:
1631
- {
1632
- "elementId": "123",
1633
- "action": "update",
1634
- "interactionId": "123",
1635
- "animationData": {
1636
- "trigger": "click",
1637
- "effect": "fade",
1638
- }
1639
- }
1640
- Example Delete Request:
1641
- {
1642
- "elementId": "123",
1643
- "action": "delete",
1644
- "interactionId": "123",
1645
- }
1646
- Example Clear Request:
1647
- {
1648
- "elementId": "123",
1649
- "action": "clear",
1650
- }
1651
- `
1652
- });
1653
- reg.waitForReady().then(() => {
1654
- initInteractionsSchemaResource(reg);
1655
- initManageElementInteractionTool(reg);
1656
- });
2142
+ var initMcpInteractions = (reg) => {
2143
+ const { setMCPDescription } = reg;
2144
+ setMCPDescription(
2145
+ `Everything related to V4 ( Atomic ) interactions.
2146
+ # Interactions
2147
+ - Create/update/delete interactions
2148
+ - Get list of interactions
2149
+ - Get details of an interaction
2150
+ `
2151
+ );
2152
+ initInteractionsSchemaResource(reg);
2153
+ initManageElementInteractionTool(reg);
1657
2154
  };
1658
2155
 
1659
2156
  // src/init.ts
@@ -1661,6 +2158,7 @@ function init() {
1661
2158
  try {
1662
2159
  interactionsRepository.register(documentElementsInteractionsProvider);
1663
2160
  initCleanInteractionIdsOnDuplicate();
2161
+ initPasteInteractionsCommand();
1664
2162
  registerInteractionsControl({
1665
2163
  type: "trigger",
1666
2164
  component: Trigger,
@@ -1674,7 +2172,7 @@ function init() {
1674
2172
  registerInteractionsControl({
1675
2173
  type: "replay",
1676
2174
  component: Replay,
1677
- options: ["true", "false"]
2175
+ options: ["no"]
1678
2176
  });
1679
2177
  registerInteractionsControl({
1680
2178
  type: "effectType",
@@ -1691,7 +2189,11 @@ function init() {
1691
2189
  component: Effect,
1692
2190
  options: ["fade", "slide", "scale"]
1693
2191
  });
1694
- initMcpInteractions();
2192
+ registerInteractionsControl({
2193
+ type: "repeat",
2194
+ component: Repeat
2195
+ });
2196
+ initMcpInteractions((0, import_editor_mcp.getMCPByDomain)("interactions", { instructions: EDITOR_INTERACTIONS_MCP_INSTRUCTIONS }));
1695
2197
  } catch (error) {
1696
2198
  throw error;
1697
2199
  }
@@ -1707,12 +2209,37 @@ function init() {
1707
2209
  ELEMENTS_INTERACTIONS_PROVIDER_KEY_PREFIX,
1708
2210
  EmptyState,
1709
2211
  InteractionsTab,
2212
+ REPEAT_OPTIONS,
2213
+ REPEAT_TOOLTIPS,
1710
2214
  REPLAY_OPTIONS,
1711
2215
  TRIGGER_OPTIONS,
2216
+ buildDisplayLabel,
2217
+ convertTimeUnit,
2218
+ createAnimationPreset,
2219
+ createBoolean,
2220
+ createConfig,
2221
+ createDefaultInteractionItem,
2222
+ createDefaultInteractions,
2223
+ createExcludedBreakpoints,
2224
+ createInteractionBreakpoints,
2225
+ createInteractionItem,
1712
2226
  createInteractionsProvider,
2227
+ createNumber,
2228
+ createString,
2229
+ createTimingConfig,
2230
+ extractBoolean,
2231
+ extractExcludedBreakpoints,
2232
+ extractSize,
2233
+ extractString,
2234
+ formatSizeValue,
2235
+ generateTempInteractionId,
1713
2236
  getInteractionsConfig,
1714
2237
  init,
1715
2238
  interactionsRepository,
1716
- registerInteractionsControl
2239
+ isTempId,
2240
+ parseSizeValue,
2241
+ registerInteractionsControl,
2242
+ resolveDirection,
2243
+ useElementInteractions
1717
2244
  });
1718
2245
  //# sourceMappingURL=index.js.map