@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.mjs CHANGED
@@ -26,8 +26,7 @@ var EmptyState = ({ onCreateInteraction }) => {
26
26
 
27
27
  // src/components/interactions-tab.tsx
28
28
  import * as React11 from "react";
29
- import { useCallback as useCallback6, useState as useState3 } from "react";
30
- import { useElementInteractions as useElementInteractions2 } from "@elementor/editor-elements";
29
+ import { useCallback as useCallback6, useState as useState4 } from "react";
31
30
  import { SessionStorageProvider } from "@elementor/session";
32
31
  import { Stack as Stack3 } from "@elementor/ui";
33
32
 
@@ -36,84 +35,28 @@ import * as React2 from "react";
36
35
  import { createContext, useContext, useEffect } from "react";
37
36
  import {
38
37
  playElementInteractions,
39
- updateElementInteractions,
40
- useElementInteractions
38
+ updateElementInteractions
41
39
  } from "@elementor/editor-elements";
42
- var InteractionsContext = createContext(null);
43
- var DEFAULT_INTERACTIONS = {
44
- version: 1,
45
- items: []
46
- };
47
- var InteractionsProvider = ({ children, elementId }) => {
48
- const rawInteractions = useElementInteractions(elementId);
49
- useEffect(() => {
50
- window.dispatchEvent(new CustomEvent("elementor/element/update_interactions"));
51
- }, []);
52
- const interactions = rawInteractions ?? DEFAULT_INTERACTIONS;
53
- const setInteractions = (value) => {
54
- const normalizedValue = value && value.items?.length === 0 ? void 0 : value;
55
- updateElementInteractions({
56
- elementId,
57
- interactions: normalizedValue
58
- });
59
- };
60
- const playInteractions = (interactionId) => {
61
- playElementInteractions(elementId, interactionId);
62
- };
63
- const contextValue = {
64
- interactions,
65
- setInteractions,
66
- playInteractions
67
- };
68
- return /* @__PURE__ */ React2.createElement(InteractionsContext.Provider, { value: contextValue }, children);
69
- };
70
- var useInteractionsContext = () => {
71
- const context = useContext(InteractionsContext);
72
- if (!context) {
73
- throw new Error("useInteractionsContext must be used within InteractionsProvider");
74
- }
75
- return context;
76
- };
77
40
 
78
- // src/contexts/popup-state-context.tsx
79
- import * as React3 from "react";
80
- import { createContext as createContext2, useCallback, useContext as useContext2, useState } from "react";
81
- var PopupStateContext = createContext2(void 0);
82
- var PopupStateProvider = ({ children }) => {
83
- const [openByDefault, setOpenByDefault] = useState(false);
84
- const triggerDefaultOpen = useCallback(() => {
85
- setOpenByDefault(true);
86
- }, []);
87
- const resetDefaultOpen = useCallback(() => {
88
- setOpenByDefault(false);
89
- }, []);
90
- return /* @__PURE__ */ React3.createElement(PopupStateContext.Provider, { value: { openByDefault, triggerDefaultOpen, resetDefaultOpen } }, children);
91
- };
41
+ // src/hooks/use-element-interactions.ts
42
+ import { useState } from "react";
43
+ import { getElementInteractions } from "@elementor/editor-elements";
44
+ import { __privateUseListenTo as useListenTo, windowEvent } from "@elementor/editor-v1-adapters";
92
45
 
93
- // src/components/interactions-list.tsx
94
- import * as React10 from "react";
95
- import { useCallback as useCallback5, useEffect as useEffect2, useMemo as useMemo3, useRef as useRef3 } from "react";
96
- import { Repeater } from "@elementor/editor-controls";
97
- import { InfoCircleFilledIcon, PlayerPlayIcon } from "@elementor/icons";
98
- import { Alert, AlertTitle, Box as Box2, IconButton, Tooltip } from "@elementor/ui";
99
- import { __ as __5 } from "@wordpress/i18n";
100
-
101
- // src/contexts/interactions-item-context.tsx
102
- import * as React4 from "react";
103
- import { createContext as createContext3, useContext as useContext3 } from "react";
104
- var InteractionItemContext = createContext3(null);
105
- function InteractionItemContextProvider({
106
- value,
107
- children
46
+ // src/interactions-controls-registry.ts
47
+ var controlsRegistry = /* @__PURE__ */ new Map();
48
+ function registerInteractionsControl({
49
+ type,
50
+ component,
51
+ options
108
52
  }) {
109
- return /* @__PURE__ */ React4.createElement(InteractionItemContext.Provider, { value }, children);
53
+ controlsRegistry.set(type, { type, component, options });
110
54
  }
111
- function useInteractionItemContext() {
112
- const context = useContext3(InteractionItemContext);
113
- if (!context) {
114
- throw new Error("useInteractionItemContext must be used within InteractionItemContextProvider");
115
- }
116
- return context;
55
+ function getInteractionsControl(type) {
56
+ return controlsRegistry.get(type);
57
+ }
58
+ function getInteractionsControlOptions(type) {
59
+ return controlsRegistry.get(type)?.options ?? [];
117
60
  }
118
61
 
119
62
  // src/utils/prop-value-utils.ts
@@ -172,17 +115,134 @@ var createSizeValue = (size, unit) => {
172
115
  return { size, unit };
173
116
  };
174
117
 
118
+ // src/utils/custom-effect-to-prop-value.ts
119
+ var CUSTOM_EFFECT_TYPE = "custom-effect";
120
+ var KEYFRAMES_TYPE = "keyframes";
121
+ var KEYFRAME_STOP_TYPE = "keyframe-stop";
122
+ var KEYFRAME_STOP_SETTINGS_TYPE = "keyframe-stop-settings";
123
+ var SIZE_TYPE = "size";
124
+ var NUMBER_TYPE = "number";
125
+ var TRANSFORM_SCALE_TYPE = "transform-scale";
126
+ var TRANSFORM_ROTATE_TYPE = "transform-rotate";
127
+ var TRANSFORM_MOVE_TYPE = "transform-move";
128
+ var TRANSFORM_SKEW_TYPE = "transform-skew";
129
+ var UNIT_PERCENT = "%";
130
+ var UNIT_DEG = "deg";
131
+ var UNIT_PX = "px";
132
+ var isPlainCustomEffect = (v) => typeof v === "object" && v !== null && "keyframes" in v && Array.isArray(v.keyframes) && !("$$type" in v);
133
+ var toSizePropValue = (size, unit = UNIT_PERCENT) => ({
134
+ $$type: SIZE_TYPE,
135
+ value: { size, unit }
136
+ });
137
+ var toNumberPropValue = (n) => ({
138
+ $$type: NUMBER_TYPE,
139
+ value: n
140
+ });
141
+ var toDimensionalNumberPropValue = (type, plain, defaults) => ({
142
+ $$type: type,
143
+ value: {
144
+ x: toNumberPropValue(plain.x ?? defaults.x),
145
+ y: toNumberPropValue(plain.y ?? defaults.y),
146
+ z: toNumberPropValue(plain.z ?? defaults.z)
147
+ }
148
+ });
149
+ var toDimensionalSizePropValue = (type, plain, defaults, unit) => ({
150
+ $$type: type,
151
+ value: {
152
+ x: toSizePropValue(plain.x ?? defaults.x, unit),
153
+ y: toSizePropValue(plain.y ?? defaults.y, unit),
154
+ z: toSizePropValue(plain.z ?? defaults.z, unit)
155
+ }
156
+ });
157
+ var toSkewPropValue = (plain) => ({
158
+ $$type: TRANSFORM_SKEW_TYPE,
159
+ value: {
160
+ x: toSizePropValue(plain.x ?? 0, UNIT_DEG),
161
+ y: toSizePropValue(plain.y ?? 0, UNIT_DEG)
162
+ }
163
+ });
164
+ var toKeyframeStopSettingsPropValue = (plain) => {
165
+ const value = {};
166
+ if (plain.opacity !== void 0) {
167
+ const percent = plain.opacity <= 1 ? Math.round(plain.opacity * 100) : plain.opacity;
168
+ value.opacity = toSizePropValue(percent);
169
+ }
170
+ if (plain.scale !== void 0) {
171
+ value.scale = toDimensionalNumberPropValue(TRANSFORM_SCALE_TYPE, plain.scale, { x: 1, y: 1, z: 1 });
172
+ }
173
+ if (plain.rotate !== void 0) {
174
+ value.rotate = toDimensionalSizePropValue(
175
+ TRANSFORM_ROTATE_TYPE,
176
+ plain.rotate,
177
+ { x: 0, y: 0, z: 0 },
178
+ UNIT_DEG
179
+ );
180
+ }
181
+ if (plain.move !== void 0) {
182
+ value.move = toDimensionalSizePropValue(TRANSFORM_MOVE_TYPE, plain.move, { x: 0, y: 0, z: 0 }, UNIT_PX);
183
+ }
184
+ if (plain.skew !== void 0) {
185
+ value.skew = toSkewPropValue(plain.skew);
186
+ }
187
+ return { $$type: KEYFRAME_STOP_SETTINGS_TYPE, value };
188
+ };
189
+ var isPlainKeyframe = (v) => typeof v === "object" && v !== null && "stop" in v && "value" in v && !("$$type" in v);
190
+ var toKeyframeStopPropValue = (item) => {
191
+ if (!isPlainKeyframe(item)) {
192
+ return item;
193
+ }
194
+ return {
195
+ $$type: KEYFRAME_STOP_TYPE,
196
+ value: {
197
+ stop: toSizePropValue(item.stop),
198
+ settings: toKeyframeStopSettingsPropValue(item.value)
199
+ }
200
+ };
201
+ };
202
+ var toKeyframesPropValue = (keyframes) => ({
203
+ $$type: KEYFRAMES_TYPE,
204
+ value: keyframes.map(toKeyframeStopPropValue)
205
+ });
206
+ var plainCustomEffectToPropValue = (plain) => ({
207
+ $$type: CUSTOM_EFFECT_TYPE,
208
+ value: {
209
+ keyframes: toKeyframesPropValue(plain.keyframes)
210
+ }
211
+ });
212
+ var toCustomEffectPropValue = (customEffects) => {
213
+ if (customEffects === void 0) {
214
+ return void 0;
215
+ }
216
+ if (isPlainCustomEffect(customEffects)) {
217
+ return plainCustomEffectToPropValue(customEffects);
218
+ }
219
+ return customEffects;
220
+ };
221
+
222
+ // src/utils/get-interactions-config.ts
223
+ function getInteractionsConfig() {
224
+ return window.ElementorInteractionsConfig ?? {};
225
+ }
226
+
175
227
  // src/utils/temp-id-utils.ts
176
228
  var TEMP_ID_PREFIX = "temp-";
229
+ var TEMP_ID_REGEX = /^temp-[a-z0-9]+$/i;
177
230
  function generateTempInteractionId() {
178
231
  return `${TEMP_ID_PREFIX}${Math.random().toString(36).substring(2, 11)}`;
179
232
  }
233
+ function isTempId(id) {
234
+ return !!id && TEMP_ID_REGEX.test(id);
235
+ }
180
236
 
181
237
  // src/utils/prop-value-utils.ts
182
238
  var createString = (value) => ({
183
239
  $$type: "string",
184
240
  value
185
241
  });
242
+ var createNumber = (value) => ({
243
+ $$type: "number",
244
+ value
245
+ });
186
246
  var createTimingConfig = (duration, delay) => ({
187
247
  $$type: "timing-config",
188
248
  value: {
@@ -197,7 +257,9 @@ var createBoolean = (value) => ({
197
257
  var createConfig = ({
198
258
  replay,
199
259
  easing = "easeIn",
200
- relativeTo = "",
260
+ relativeTo = "viewport",
261
+ repeat = "",
262
+ times = 1,
201
263
  start = 85,
202
264
  end = 15
203
265
  }) => ({
@@ -206,6 +268,8 @@ var createConfig = ({
206
268
  replay: createBoolean(replay),
207
269
  easing: createString(easing),
208
270
  relativeTo: createString(relativeTo),
271
+ repeat: createString(repeat),
272
+ times: createNumber(times),
209
273
  start: createSize(start, "%"),
210
274
  end: createSize(end, "%")
211
275
  }
@@ -241,26 +305,33 @@ var createAnimationPreset = ({
241
305
  replay = false,
242
306
  easing = "easeIn",
243
307
  relativeTo,
308
+ repeat,
309
+ times,
244
310
  start,
245
311
  end,
246
312
  customEffects
247
- }) => ({
248
- $$type: "animation-preset-props",
249
- value: {
250
- effect: createString(effect),
251
- custom_effect: customEffects,
252
- type: createString(type),
253
- direction: createString(direction ?? ""),
254
- timing_config: createTimingConfig(duration, delay),
255
- config: createConfig({
256
- replay,
257
- easing,
258
- relativeTo,
259
- start,
260
- end
261
- })
262
- }
263
- });
313
+ }) => {
314
+ const customEffectProp = toCustomEffectPropValue(customEffects);
315
+ return {
316
+ $$type: "animation-preset-props",
317
+ value: {
318
+ effect: createString(effect),
319
+ ...customEffectProp !== void 0 && { custom_effect: customEffectProp },
320
+ type: createString(type),
321
+ direction: createString(direction ?? ""),
322
+ timing_config: createTimingConfig(duration, delay),
323
+ config: createConfig({
324
+ replay,
325
+ easing,
326
+ relativeTo,
327
+ repeat,
328
+ times,
329
+ start,
330
+ end
331
+ })
332
+ }
333
+ };
334
+ };
264
335
  var createInteractionItem = ({
265
336
  trigger,
266
337
  effect,
@@ -272,6 +343,8 @@ var createInteractionItem = ({
272
343
  replay = false,
273
344
  easing = "easeIn",
274
345
  relativeTo,
346
+ repeat,
347
+ times,
275
348
  start,
276
349
  end,
277
350
  excludedBreakpoints,
@@ -290,6 +363,8 @@ var createInteractionItem = ({
290
363
  replay,
291
364
  easing,
292
365
  relativeTo,
366
+ repeat,
367
+ times,
293
368
  start,
294
369
  end,
295
370
  customEffects
@@ -300,17 +375,22 @@ var createInteractionItem = ({
300
375
  }
301
376
  });
302
377
  var createDefaultInteractionItem = () => {
378
+ const { constants } = getInteractionsConfig();
303
379
  return createInteractionItem({
304
380
  trigger: "load",
305
381
  effect: "fade",
306
382
  type: "in",
307
- duration: 600,
308
- delay: 0,
383
+ duration: constants.defaultDuration,
384
+ delay: constants.defaultDelay,
309
385
  replay: false,
310
- easing: "easeIn",
386
+ easing: constants.defaultEasing,
311
387
  interactionId: generateTempInteractionId()
312
388
  });
313
389
  };
390
+ var createDefaultInteractions = () => ({
391
+ version: 1,
392
+ items: [createDefaultInteractionItem()]
393
+ });
314
394
  var extractString = (prop, fallback = "") => {
315
395
  return prop?.value ?? fallback;
316
396
  };
@@ -335,10 +415,180 @@ var buildDisplayLabel = (item) => {
335
415
  const type = extractString(item.animation.value.type);
336
416
  const triggerLabel = TRIGGER_LABELS[trigger] || capitalize(trigger);
337
417
  const effectLabel = capitalize(effect);
338
- const typeLabel = capitalize(type);
418
+ const typeLabel = "custom" === effect ? "" : capitalize(type);
339
419
  return `${triggerLabel}: ${effectLabel} ${typeLabel}`;
340
420
  };
341
421
 
422
+ // src/utils/is-supported-interaction-item.ts
423
+ function isSupportedInteractionItem(interaction) {
424
+ const value = interaction.value;
425
+ const replay = extractBoolean(value.animation.value.config?.value.replay);
426
+ if (true === replay) {
427
+ return hasSupport("replay", "yes");
428
+ }
429
+ const trigger = extractString(value.trigger);
430
+ const easing = extractString(value.animation.value.config?.value.easing);
431
+ const effect = extractString(value.animation.value.effect);
432
+ const checks = [
433
+ ["trigger", trigger],
434
+ ["easing", easing],
435
+ ["effect", effect]
436
+ ];
437
+ return checks.every(([controlType, controlValue]) => {
438
+ if (controlValue === "" || controlValue === null) {
439
+ return true;
440
+ }
441
+ return hasSupport(controlType, controlValue);
442
+ });
443
+ }
444
+ function hasSupport(controlType, controlValue) {
445
+ const supportedOptions = getInteractionsControlOptions(controlType);
446
+ if (1 > supportedOptions.length) {
447
+ return true;
448
+ }
449
+ return supportedOptions.includes(controlValue);
450
+ }
451
+
452
+ // src/utils/filter-interactions.ts
453
+ var filterInteractions = (interactions) => {
454
+ return interactions.filter((interaction) => {
455
+ return isSupportedInteractionItem(interaction);
456
+ });
457
+ };
458
+
459
+ // src/hooks/use-element-interactions.ts
460
+ var useElementInteractions = (elementId) => {
461
+ const [interactions, setInteractions] = useState(() => {
462
+ const initial = getElementInteractions(elementId);
463
+ const filteredInteractions = filterInteractions(initial?.items ?? []);
464
+ return { version: initial?.version ?? 1, items: filteredInteractions };
465
+ });
466
+ useListenTo(
467
+ windowEvent("elementor/element/update_interactions"),
468
+ () => {
469
+ const newInteractions = getElementInteractions(elementId);
470
+ const filteredInteractions = filterInteractions(newInteractions?.items ?? []);
471
+ setInteractions({ version: newInteractions?.version ?? 1, items: filteredInteractions });
472
+ },
473
+ [elementId]
474
+ );
475
+ return interactions;
476
+ };
477
+
478
+ // src/contexts/interactions-context.tsx
479
+ var InteractionsContext = createContext(null);
480
+ var DEFAULT_INTERACTIONS = {
481
+ version: 1,
482
+ items: []
483
+ };
484
+ var InteractionsProvider = ({ children, elementId }) => {
485
+ const rawInteractions = useElementInteractions(elementId);
486
+ useEffect(() => {
487
+ window.dispatchEvent(new CustomEvent("elementor/element/update_interactions"));
488
+ }, []);
489
+ const interactions = rawInteractions ?? DEFAULT_INTERACTIONS;
490
+ const setInteractions = (value) => {
491
+ const normalizedValue = value && value.items?.length === 0 ? void 0 : value;
492
+ updateElementInteractions({
493
+ elementId,
494
+ interactions: normalizedValue
495
+ });
496
+ };
497
+ const playInteractions = (interactionId) => {
498
+ playElementInteractions(elementId, interactionId);
499
+ };
500
+ const contextValue = {
501
+ elementId,
502
+ interactions,
503
+ setInteractions,
504
+ playInteractions
505
+ };
506
+ return /* @__PURE__ */ React2.createElement(InteractionsContext.Provider, { value: contextValue }, children);
507
+ };
508
+ var useInteractionsContext = () => {
509
+ const context = useContext(InteractionsContext);
510
+ if (!context) {
511
+ throw new Error("useInteractionsContext must be used within InteractionsProvider");
512
+ }
513
+ return context;
514
+ };
515
+
516
+ // src/contexts/popup-state-context.tsx
517
+ import * as React3 from "react";
518
+ import { createContext as createContext2, useCallback, useContext as useContext2, useState as useState2 } from "react";
519
+ var PopupStateContext = createContext2(void 0);
520
+ var PopupStateProvider = ({ children }) => {
521
+ const [openByDefault, setOpenByDefault] = useState2(false);
522
+ const triggerDefaultOpen = useCallback(() => {
523
+ setOpenByDefault(true);
524
+ }, []);
525
+ const resetDefaultOpen = useCallback(() => {
526
+ setOpenByDefault(false);
527
+ }, []);
528
+ return /* @__PURE__ */ React3.createElement(PopupStateContext.Provider, { value: { openByDefault, triggerDefaultOpen, resetDefaultOpen } }, children);
529
+ };
530
+
531
+ // src/utils/tracking.ts
532
+ import { getElementLabel } from "@elementor/editor-elements";
533
+ import { getMixpanel } from "@elementor/events";
534
+ var TRIGGER_LABELS2 = {
535
+ load: "On page load",
536
+ scrollIn: "Scroll into view",
537
+ scrollOut: "Scroll out of view",
538
+ scrollOn: "While scrolling",
539
+ hover: "Hover",
540
+ click: "Click"
541
+ };
542
+ var capitalize2 = (s) => s.charAt(0).toUpperCase() + s.slice(1);
543
+ var trackInteractionCreated = (elementId, item) => {
544
+ const { dispatchEvent, config } = getMixpanel();
545
+ if (!config?.names?.interactions?.created) {
546
+ return;
547
+ }
548
+ const trigger = extractString(item.value.trigger);
549
+ const effect = extractString(item.value.animation.value.effect);
550
+ const type = extractString(item.value.animation.value.type);
551
+ dispatchEvent?.(config.names.interactions.created, {
552
+ app_type: config?.appTypes?.editor,
553
+ window_name: config?.appTypes?.editor,
554
+ interaction_type: config?.triggers?.click,
555
+ target_name: getElementLabel(elementId),
556
+ interaction_result: "interaction_created",
557
+ target_location: config?.locations?.widgetPanel,
558
+ location_l1: getElementLabel(elementId),
559
+ location_l2: "interactions",
560
+ interaction_description: "interaction_created",
561
+ interaction_trigger: TRIGGER_LABELS2[trigger] ?? capitalize2(trigger),
562
+ interaction_effect: effect === "custom" ? capitalize2(effect) : `${capitalize2(effect)} ${capitalize2(type)}`
563
+ });
564
+ };
565
+
566
+ // src/components/interactions-list.tsx
567
+ import * as React10 from "react";
568
+ import { useCallback as useCallback5, useEffect as useEffect2, useMemo as useMemo3, useRef as useRef2 } from "react";
569
+ import { Repeater } from "@elementor/editor-controls";
570
+ import { InfoCircleFilledIcon, PlayerPlayIcon } from "@elementor/icons";
571
+ import { Alert, AlertTitle, Box, IconButton, Tooltip } from "@elementor/ui";
572
+ import { __ as __5 } from "@wordpress/i18n";
573
+
574
+ // src/contexts/interactions-item-context.tsx
575
+ import * as React4 from "react";
576
+ import { createContext as createContext3, useContext as useContext3 } from "react";
577
+ var InteractionItemContext = createContext3(null);
578
+ function InteractionItemContextProvider({
579
+ value,
580
+ children
581
+ }) {
582
+ return /* @__PURE__ */ React4.createElement(InteractionItemContext.Provider, { value }, children);
583
+ }
584
+ function useInteractionItemContext() {
585
+ const context = useContext3(InteractionItemContext);
586
+ if (!context) {
587
+ throw new Error("useInteractionItemContext must be used within InteractionItemContextProvider");
588
+ }
589
+ return context;
590
+ }
591
+
342
592
  // src/components/interactions-list-item.tsx
343
593
  import * as React9 from "react";
344
594
  import { useCallback as useCallback4 } from "react";
@@ -347,24 +597,11 @@ import { __ as __4 } from "@wordpress/i18n";
347
597
 
348
598
  // src/components/interaction-details.tsx
349
599
  import * as React7 from "react";
350
- import { useMemo, useRef as useRef2 } from "react";
600
+ import { useMemo } from "react";
351
601
  import { PopoverContent } from "@elementor/editor-controls";
352
- import { Box, Divider, Grid as Grid2 } from "@elementor/ui";
602
+ import { Divider, Grid as Grid2 } from "@elementor/ui";
353
603
  import { __ as __2 } from "@wordpress/i18n";
354
604
 
355
- // src/interactions-controls-registry.ts
356
- var controlsRegistry = /* @__PURE__ */ new Map();
357
- function registerInteractionsControl({
358
- type,
359
- component,
360
- options
361
- }) {
362
- controlsRegistry.set(type, { type, component, options });
363
- }
364
- function getInteractionsControl(type) {
365
- return controlsRegistry.get(type);
366
- }
367
-
368
605
  // src/utils/resolve-direction.ts
369
606
  var resolveDirection = (hasDirection, newEffect, newDirection, currentDirection, currentEffect) => {
370
607
  if (newEffect === "slide" && !newDirection) {
@@ -457,6 +694,8 @@ var DEFAULT_VALUES = {
457
694
  replay: false,
458
695
  easing: "easeIn",
459
696
  relativeTo: "viewport",
697
+ repeat: "",
698
+ times: 1,
460
699
  start: 85,
461
700
  end: 15
462
701
  };
@@ -469,6 +708,8 @@ var controlVisibilityConfig = {
469
708
  relativeTo: (values) => values.trigger === "scrollOn",
470
709
  start: (values) => values.trigger === "scrollOn",
471
710
  end: (values) => values.trigger === "scrollOn",
711
+ repeat: (values) => values.trigger !== "scrollOn",
712
+ times: (values) => values.trigger !== "scrollOn" && values.repeat === "times",
472
713
  duration: (values) => {
473
714
  const isRelativeToVisible = values.trigger === "scrollOn";
474
715
  return !isRelativeToVisible;
@@ -478,6 +719,13 @@ var controlVisibilityConfig = {
478
719
  return !isRelativeToVisible;
479
720
  }
480
721
  };
722
+ function normalizeTimesValue(value, fallback) {
723
+ const numericValue = Number(value);
724
+ if (!Number.isFinite(numericValue)) {
725
+ return fallback;
726
+ }
727
+ return Math.max(1, Math.floor(numericValue));
728
+ }
481
729
  function useControlComponent(controlName, isVisible = true) {
482
730
  return useMemo(() => {
483
731
  if (!isVisible) {
@@ -497,6 +745,9 @@ var InteractionDetails = ({ interaction, onChange, onPlayInteraction }) => {
497
745
  const replay = extractBoolean(interaction.animation.value.config?.value.replay, DEFAULT_VALUES.replay);
498
746
  const easing = extractString(interaction.animation.value.config?.value.easing, DEFAULT_VALUES.easing);
499
747
  const relativeTo = extractString(interaction.animation.value.config?.value.relativeTo, DEFAULT_VALUES.relativeTo);
748
+ const configValue = interaction.animation.value.config?.value;
749
+ const repeat = extractString(configValue?.repeat, DEFAULT_VALUES.repeat);
750
+ const times = normalizeTimesValue(configValue?.times?.value, DEFAULT_VALUES.times);
500
751
  const start = extractSize(interaction.animation.value.config?.value.start, DEFAULT_VALUES.start);
501
752
  const end = extractSize(interaction.animation.value.config?.value.end, DEFAULT_VALUES.end);
502
753
  const interactionValues = {
@@ -509,6 +760,8 @@ var InteractionDetails = ({ interaction, onChange, onPlayInteraction }) => {
509
760
  easing,
510
761
  replay,
511
762
  relativeTo,
763
+ repeat,
764
+ times,
512
765
  start,
513
766
  end,
514
767
  customEffects
@@ -531,8 +784,15 @@ var InteractionDetails = ({ interaction, onChange, onPlayInteraction }) => {
531
784
  controlVisibilityConfig.effectType(interactionValues)
532
785
  );
533
786
  const DirectionControl = useControlComponent("direction", controlVisibilityConfig.direction(interactionValues));
787
+ const RepeatControl = useControlComponent(
788
+ "repeat",
789
+ controlVisibilityConfig.repeat(interactionValues)
790
+ );
791
+ const TimesControl = useControlComponent(
792
+ "times",
793
+ controlVisibilityConfig.times(interactionValues)
794
+ );
534
795
  const EasingControl = useControlComponent("easing");
535
- const containerRef = useRef2(null);
536
796
  const updateInteraction = (updates) => {
537
797
  const resolvedDirectionValue = resolveDirection(
538
798
  "direction" in updates,
@@ -554,6 +814,8 @@ var InteractionDetails = ({ interaction, onChange, onPlayInteraction }) => {
554
814
  replay: updates.replay ?? replay,
555
815
  easing: updates.easing ?? easing,
556
816
  relativeTo: updates.relativeTo ?? relativeTo,
817
+ repeat: updates.repeat ?? repeat,
818
+ times: updates.times ?? times,
557
819
  start: updates.start ?? start,
558
820
  end: updates.end ?? end,
559
821
  customEffects: updates.customEffects ?? customEffects
@@ -565,19 +827,12 @@ var InteractionDetails = ({ interaction, onChange, onPlayInteraction }) => {
565
827
  onPlayInteraction(interactionId);
566
828
  }, 0);
567
829
  };
568
- return /* @__PURE__ */ React7.createElement(Box, { ref: containerRef }, /* @__PURE__ */ React7.createElement(PopoverContent, { p: 1.5 }, /* @__PURE__ */ React7.createElement(Grid2, { container: true, spacing: 1.5 }, TriggerControl && /* @__PURE__ */ React7.createElement(Field, { label: __2("Trigger", "elementor") }, /* @__PURE__ */ React7.createElement(
569
- TriggerControl,
570
- {
571
- value: trigger,
572
- onChange: (v) => updateInteraction({ trigger: v })
573
- }
574
- )), ReplayControl && /* @__PURE__ */ React7.createElement(Field, { label: __2("Replay", "elementor") }, /* @__PURE__ */ React7.createElement(
830
+ return /* @__PURE__ */ React7.createElement(PopoverContent, { p: 1.5 }, /* @__PURE__ */ React7.createElement(Grid2, { container: true, spacing: 1.5 }, TriggerControl && /* @__PURE__ */ React7.createElement(Field, { label: __2("Trigger", "elementor") }, /* @__PURE__ */ React7.createElement(TriggerControl, { value: trigger, onChange: (v) => updateInteraction({ trigger: v }) })), ReplayControl && /* @__PURE__ */ React7.createElement(Field, { label: __2("Replay", "elementor") }, /* @__PURE__ */ React7.createElement(
575
831
  ReplayControl,
576
832
  {
577
833
  value: replay,
578
834
  onChange: (v) => updateInteraction({ replay: v }),
579
- disabled: true,
580
- anchorRef: containerRef
835
+ disabled: true
581
836
  }
582
837
  ))), /* @__PURE__ */ React7.createElement(Divider, null), /* @__PURE__ */ React7.createElement(Grid2, { container: true, spacing: 1.5 }, EffectControl && /* @__PURE__ */ React7.createElement(Field, { label: __2("Effect", "elementor") }, /* @__PURE__ */ React7.createElement(EffectControl, { value: effect, onChange: (v) => updateInteraction({ effect: v }) })), CustomEffectControl && /* @__PURE__ */ React7.createElement(Field, { label: __2("Custom Effect", "elementor") }, /* @__PURE__ */ React7.createElement(
583
838
  CustomEffectControl,
@@ -592,6 +847,14 @@ var InteractionDetails = ({ interaction, onChange, onPlayInteraction }) => {
592
847
  onChange: (v) => updateInteraction({ direction: v }),
593
848
  interactionType: type
594
849
  }
850
+ )), RepeatControl && /* @__PURE__ */ React7.createElement(Field, { label: __2("Repeat", "elementor") }, /* @__PURE__ */ React7.createElement(RepeatControl, { value: repeat, onChange: (v) => updateInteraction({ repeat: v }) })), TimesControl && /* @__PURE__ */ React7.createElement(Field, { label: __2("Times", "elementor") }, /* @__PURE__ */ React7.createElement(
851
+ TimesControl,
852
+ {
853
+ value: times,
854
+ onChange: (v) => updateInteraction({
855
+ times: normalizeTimesValue(v, DEFAULT_VALUES.times)
856
+ })
857
+ }
595
858
  )), controlVisibilityConfig.duration(interactionValues) && /* @__PURE__ */ React7.createElement(Field, { label: __2("Duration", "elementor") }, /* @__PURE__ */ React7.createElement(
596
859
  TimeFrameIndicator,
597
860
  {
@@ -632,12 +895,12 @@ var InteractionDetails = ({ interaction, onChange, onPlayInteraction }) => {
632
895
  updateInteraction({ easing: v });
633
896
  }
634
897
  }
635
- )))));
898
+ ))));
636
899
  };
637
900
 
638
901
  // src/components/interaction-settings.tsx
639
902
  import * as React8 from "react";
640
- import { useCallback as useCallback3, useMemo as useMemo2, useState as useState2 } from "react";
903
+ import { useCallback as useCallback3, useMemo as useMemo2, useState as useState3 } from "react";
641
904
  import { ControlFormLabel as ControlFormLabel2, PopoverContent as PopoverContent2 } from "@elementor/editor-controls";
642
905
  import { useBreakpoints } from "@elementor/editor-responsive";
643
906
  import { Autocomplete, Chip, Grid as Grid3, Stack as Stack2, TextField } from "@elementor/ui";
@@ -649,7 +912,7 @@ var InteractionSettings = ({ interaction, onChange }) => {
649
912
  () => breakpoints.map((breakpoint) => ({ label: breakpoint.label, value: String(breakpoint.id) })),
650
913
  [breakpoints]
651
914
  );
652
- const [selectedBreakpoints, setSelectedBreakpoints] = useState2(() => {
915
+ const [selectedBreakpoints, setSelectedBreakpoints] = useState3(() => {
653
916
  const excluded = extractExcludedBreakpoints(interaction.breakpoints).filter((excludedBreakpoint) => {
654
917
  return availableBreakpoints.some(({ value }) => value === excludedBreakpoint);
655
918
  });
@@ -746,7 +1009,8 @@ var InteractionsListItem = ({
746
1009
  var MAX_NUMBER_OF_INTERACTIONS = 5;
747
1010
  function InteractionsList(props) {
748
1011
  const { interactions, onSelectInteractions, onPlayInteraction, triggerCreateOnShowEmpty } = props;
749
- const hasInitializedRef = useRef3(false);
1012
+ const { elementId } = useInteractionsContext();
1013
+ const hasInitializedRef = useRef2(false);
750
1014
  const handleUpdateInteractions = useCallback5(
751
1015
  (newInteractions) => {
752
1016
  onSelectInteractions(newInteractions);
@@ -766,18 +1030,24 @@ function InteractionsList(props) {
766
1030
  const isMaxNumberOfInteractionsReached = useMemo3(() => {
767
1031
  return interactions.items?.length >= MAX_NUMBER_OF_INTERACTIONS;
768
1032
  }, [interactions.items?.length]);
769
- const infotipContent = isMaxNumberOfInteractionsReached ? /* @__PURE__ */ React10.createElement(Alert, { color: "secondary", icon: /* @__PURE__ */ React10.createElement(InfoCircleFilledIcon, null), size: "small" }, /* @__PURE__ */ React10.createElement(AlertTitle, null, __5("Interactions", "elementor")), /* @__PURE__ */ React10.createElement(Box2, { component: "span" }, __5(
1033
+ const infotipContent = isMaxNumberOfInteractionsReached ? /* @__PURE__ */ React10.createElement(Alert, { color: "secondary", icon: /* @__PURE__ */ React10.createElement(InfoCircleFilledIcon, null), size: "small" }, /* @__PURE__ */ React10.createElement(AlertTitle, null, __5("Interactions", "elementor")), /* @__PURE__ */ React10.createElement(Box, { component: "span" }, __5(
770
1034
  "You've reached the limit of 5 interactions for this element. Please remove an interaction before creating a new one.",
771
1035
  "elementor"
772
1036
  ))) : void 0;
773
1037
  const handleRepeaterChange = useCallback5(
774
- (newItems) => {
1038
+ (newItems, _, meta) => {
775
1039
  handleUpdateInteractions({
776
1040
  ...interactions,
777
1041
  items: newItems
778
1042
  });
1043
+ if (meta?.action?.type === "add") {
1044
+ const addedItem = meta.action.payload[0]?.item;
1045
+ if (addedItem) {
1046
+ trackInteractionCreated(elementId, addedItem);
1047
+ }
1048
+ }
779
1049
  },
780
- [interactions, handleUpdateInteractions]
1050
+ [interactions, handleUpdateInteractions, elementId]
781
1051
  );
782
1052
  const handleInteractionChange = useCallback5(
783
1053
  (index, newInteractionValue) => {
@@ -837,14 +1107,15 @@ var InteractionsTab = ({ elementId }) => {
837
1107
  return /* @__PURE__ */ React11.createElement(PopupStateProvider, null, /* @__PURE__ */ React11.createElement(InteractionsTabContent, { elementId }));
838
1108
  };
839
1109
  function InteractionsTabContent({ elementId }) {
840
- const existingInteractions = useElementInteractions2(elementId);
841
- const firstInteractionState = useState3(false);
1110
+ const existingInteractions = useElementInteractions(elementId);
1111
+ const firstInteractionState = useState4(false);
842
1112
  const hasInteractions = existingInteractions?.items?.length || firstInteractionState[0];
843
1113
  return /* @__PURE__ */ React11.createElement(SessionStorageProvider, { prefix: elementId }, hasInteractions ? /* @__PURE__ */ React11.createElement(InteractionsProvider, { elementId }, /* @__PURE__ */ React11.createElement(InteractionsContent, { firstInteractionState })) : /* @__PURE__ */ React11.createElement(
844
1114
  EmptyState,
845
1115
  {
846
1116
  onCreateInteraction: () => {
847
1117
  firstInteractionState[1](true);
1118
+ trackInteractionCreated(elementId, createDefaultInteractionItem());
848
1119
  }
849
1120
  }
850
1121
  ));
@@ -875,20 +1146,6 @@ function InteractionsContent({
875
1146
  ));
876
1147
  }
877
1148
 
878
- // src/utils/get-interactions-config.ts
879
- var DEFAULT_CONFIG = {
880
- constants: {
881
- defaultDuration: 300,
882
- defaultDelay: 0,
883
- slideDistance: 100,
884
- scaleStart: 0.5,
885
- easing: "linear"
886
- }
887
- };
888
- function getInteractionsConfig() {
889
- return window.ElementorInteractionsConfig || DEFAULT_CONFIG;
890
- }
891
-
892
1149
  // src/utils/create-interactions-repository.ts
893
1150
  var createInteractionsRepository = () => {
894
1151
  const providers = [];
@@ -949,8 +1206,8 @@ function createInteractionsProvider({
949
1206
  }
950
1207
 
951
1208
  // src/providers/document-elements-interactions-provider.ts
952
- import { getCurrentDocumentId, getElementInteractions, getElements } from "@elementor/editor-elements";
953
- import { __privateListenTo as listenTo, windowEvent } from "@elementor/editor-v1-adapters";
1209
+ import { getCurrentDocumentId, getElementInteractions as getElementInteractions2, getElements } from "@elementor/editor-elements";
1210
+ import { __privateListenTo as listenTo, windowEvent as windowEvent2 } from "@elementor/editor-v1-adapters";
954
1211
  var ELEMENTS_INTERACTIONS_PROVIDER_KEY_PREFIX = "document-elements-interactions-";
955
1212
  var documentElementsInteractionsProvider = createInteractionsProvider({
956
1213
  key: () => {
@@ -964,20 +1221,20 @@ var documentElementsInteractionsProvider = createInteractionsProvider({
964
1221
  },
965
1222
  priority: 50,
966
1223
  subscribe: (cb) => {
967
- return listenTo([windowEvent("elementor/element/update_interactions")], () => cb());
1224
+ return listenTo([windowEvent2("elementor/element/update_interactions")], () => cb());
968
1225
  },
969
1226
  actions: {
970
1227
  all: () => {
971
1228
  const elements = getElements();
972
1229
  const filtered = elements.filter((element) => {
973
- const interactions = getElementInteractions(element.id);
1230
+ const interactions = getElementInteractions2(element.id);
974
1231
  if (!interactions) {
975
1232
  return false;
976
1233
  }
977
1234
  return interactions?.items?.length > 0;
978
1235
  });
979
1236
  return filtered.map((element) => {
980
- const interactions = getElementInteractions(element.id);
1237
+ const interactions = getElementInteractions2(element.id);
981
1238
  return {
982
1239
  elementId: element.id,
983
1240
  dataId: element.id,
@@ -988,37 +1245,148 @@ var documentElementsInteractionsProvider = createInteractionsProvider({
988
1245
  }
989
1246
  });
990
1247
 
1248
+ // src/init.ts
1249
+ import { getMCPByDomain } from "@elementor/editor-mcp";
1250
+
1251
+ // src/commands/paste-interactions.ts
1252
+ import {
1253
+ getContainer,
1254
+ getElementInteractions as getElementInteractions3,
1255
+ getElementLabel as getElementLabel2,
1256
+ getWidgetsCache,
1257
+ updateElementInteractions as updateElementInteractions2
1258
+ } from "@elementor/editor-elements";
1259
+ import {
1260
+ __privateListenTo as listenTo2,
1261
+ commandStartEvent,
1262
+ undoable
1263
+ } from "@elementor/editor-v1-adapters";
1264
+ import { __ as __6 } from "@wordpress/i18n";
1265
+
1266
+ // src/commands/get-clipboard-elements.ts
1267
+ function getClipboardElements(storageKey = "clipboard") {
1268
+ try {
1269
+ const storedData = JSON.parse(localStorage.getItem("elementor") ?? "{}");
1270
+ return storedData[storageKey]?.elements;
1271
+ } catch {
1272
+ return void 0;
1273
+ }
1274
+ }
1275
+
1276
+ // src/commands/paste-interactions.ts
1277
+ function isAtomicContainer(container) {
1278
+ const type = container?.model.get("widgetType") || container?.model.get("elType");
1279
+ const widgetsCache = getWidgetsCache();
1280
+ const elementConfig = widgetsCache?.[type];
1281
+ return Boolean(elementConfig?.atomic_props_schema);
1282
+ }
1283
+ function getTitleForContainers(containers) {
1284
+ return containers.length > 1 ? __6("Elements", "elementor") : getElementLabel2(containers[0].id);
1285
+ }
1286
+ function normalizeClipboardInteractions(raw) {
1287
+ if (!raw) {
1288
+ return null;
1289
+ }
1290
+ const parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
1291
+ if (!parsed?.items?.length) {
1292
+ return null;
1293
+ }
1294
+ return { version: parsed.version ?? 1, items: parsed.items };
1295
+ }
1296
+ function regenerateInteractionIds(interactions) {
1297
+ const cloned = structuredClone(interactions);
1298
+ cloned.items?.forEach((item) => {
1299
+ if (item.$$type === "interaction-item" && item.value) {
1300
+ item.value.interaction_id = createString(generateTempInteractionId());
1301
+ }
1302
+ });
1303
+ return cloned;
1304
+ }
1305
+ function initPasteInteractionsCommand() {
1306
+ const undoablePasteInteractions = undoable(
1307
+ {
1308
+ do: ({ containers, newInteractions }) => {
1309
+ const pasted = regenerateInteractionIds(newInteractions);
1310
+ return containers.map((container) => {
1311
+ const elementId = container.id;
1312
+ const previous = getElementInteractions3(elementId);
1313
+ updateElementInteractions2({
1314
+ elementId,
1315
+ interactions: pasted
1316
+ });
1317
+ return { elementId, previous: previous ?? { version: 1, items: [] } };
1318
+ });
1319
+ },
1320
+ undo: (_, revertData) => {
1321
+ revertData.forEach(({ elementId, previous }) => {
1322
+ updateElementInteractions2({
1323
+ elementId,
1324
+ interactions: previous.items?.length ? previous : void 0
1325
+ });
1326
+ });
1327
+ }
1328
+ },
1329
+ {
1330
+ title: ({ containers }) => getTitleForContainers(containers),
1331
+ subtitle: __6("Interactions Pasted", "elementor")
1332
+ }
1333
+ );
1334
+ listenTo2(commandStartEvent("document/elements/paste-interactions"), (e) => {
1335
+ const args = e.args;
1336
+ const containers = args.containers ?? (args.container ? [args.container] : []);
1337
+ const storageKey = args.storageKey ?? "clipboard";
1338
+ if (!containers.length) {
1339
+ return;
1340
+ }
1341
+ const clipboardElements = getClipboardElements(storageKey);
1342
+ const [clipboardElement] = clipboardElements ?? [];
1343
+ if (!clipboardElement) {
1344
+ return;
1345
+ }
1346
+ const newInteractions = normalizeClipboardInteractions(clipboardElement.interactions);
1347
+ if (!newInteractions) {
1348
+ return;
1349
+ }
1350
+ const existingContainers = containers.filter((c) => getContainer(c.id));
1351
+ const validContainers = existingContainers.filter(isAtomicContainer);
1352
+ if (!validContainers.length) {
1353
+ return;
1354
+ }
1355
+ undoablePasteInteractions({ containers: validContainers, newInteractions });
1356
+ });
1357
+ }
1358
+
991
1359
  // src/components/controls/direction.tsx
992
1360
  import * as React12 from "react";
993
1361
  import { useMemo as useMemo4 } from "react";
994
1362
  import { ToggleButtonGroupUi } from "@elementor/editor-controls";
995
1363
  import { ArrowDownSmallIcon, ArrowLeftIcon, ArrowRightIcon, ArrowUpSmallIcon } from "@elementor/icons";
996
- import { __ as __6 } from "@wordpress/i18n";
1364
+ import { __ as __7 } from "@wordpress/i18n";
997
1365
  function Direction({ value, onChange, interactionType }) {
998
1366
  const options = useMemo4(() => {
999
1367
  const isIn = interactionType === "in";
1000
1368
  return [
1001
1369
  {
1002
1370
  value: "top",
1003
- label: isIn ? __6("From top", "elementor") : __6("To top", "elementor"),
1371
+ label: isIn ? __7("From top", "elementor") : __7("To top", "elementor"),
1004
1372
  renderContent: ({ size }) => isIn ? /* @__PURE__ */ React12.createElement(ArrowDownSmallIcon, { fontSize: size }) : /* @__PURE__ */ React12.createElement(ArrowUpSmallIcon, { fontSize: size }),
1005
1373
  showTooltip: true
1006
1374
  },
1007
1375
  {
1008
1376
  value: "bottom",
1009
- label: interactionType === "in" ? __6("From bottom", "elementor") : __6("To bottom", "elementor"),
1377
+ label: interactionType === "in" ? __7("From bottom", "elementor") : __7("To bottom", "elementor"),
1010
1378
  renderContent: ({ size }) => isIn ? /* @__PURE__ */ React12.createElement(ArrowUpSmallIcon, { fontSize: size }) : /* @__PURE__ */ React12.createElement(ArrowDownSmallIcon, { fontSize: size }),
1011
1379
  showTooltip: true
1012
1380
  },
1013
1381
  {
1014
1382
  value: "left",
1015
- label: interactionType === "in" ? __6("From left", "elementor") : __6("To left", "elementor"),
1383
+ label: interactionType === "in" ? __7("From left", "elementor") : __7("To left", "elementor"),
1016
1384
  renderContent: ({ size }) => isIn ? /* @__PURE__ */ React12.createElement(ArrowRightIcon, { fontSize: size }) : /* @__PURE__ */ React12.createElement(ArrowLeftIcon, { fontSize: size }),
1017
1385
  showTooltip: true
1018
1386
  },
1019
1387
  {
1020
1388
  value: "right",
1021
- label: interactionType === "in" ? __6("From right", "elementor") : __6("To right", "elementor"),
1389
+ label: interactionType === "in" ? __7("From right", "elementor") : __7("To right", "elementor"),
1022
1390
  renderContent: ({ size }) => isIn ? /* @__PURE__ */ React12.createElement(ArrowLeftIcon, { fontSize: size }) : /* @__PURE__ */ React12.createElement(ArrowRightIcon, { fontSize: size }),
1023
1391
  showTooltip: true
1024
1392
  }
@@ -1029,27 +1397,35 @@ function Direction({ value, onChange, interactionType }) {
1029
1397
 
1030
1398
  // src/components/controls/easing.tsx
1031
1399
  import * as React15 from "react";
1032
- import { __ as __9 } from "@wordpress/i18n";
1400
+ import { __ as __10 } from "@wordpress/i18n";
1033
1401
 
1034
1402
  // src/ui/promotion-select.tsx
1035
1403
  import * as React14 from "react";
1036
- import { useRef as useRef4 } from "react";
1404
+ import { useRef as useRef3 } from "react";
1037
1405
  import { MenuListItem } from "@elementor/editor-ui";
1038
1406
  import { MenuSubheader, Select } from "@elementor/ui";
1039
- import { __ as __8 } from "@wordpress/i18n";
1407
+ import { __ as __9 } from "@wordpress/i18n";
1040
1408
 
1041
1409
  // src/ui/interactions-promotion-chip.tsx
1042
1410
  import * as React13 from "react";
1043
- import { forwardRef, useImperativeHandle, useState as useState4 } from "react";
1411
+ import { forwardRef, useCallback as useCallback7, useImperativeHandle, useState as useState5 } from "react";
1412
+ import { trackUpgradePromotionClick, trackViewPromotion } from "@elementor/editor-controls";
1044
1413
  import { PromotionChip, PromotionPopover, useCanvasClickHandler } from "@elementor/editor-ui";
1045
- import { Box as Box3 } from "@elementor/ui";
1046
- import { __ as __7 } from "@wordpress/i18n";
1414
+ import { Box as Box2 } from "@elementor/ui";
1415
+ import { __ as __8 } from "@wordpress/i18n";
1047
1416
  var InteractionsPromotionChip = forwardRef(
1048
- ({ content, upgradeUrl, anchorRef }, ref) => {
1049
- const [isOpen, setIsOpen] = useState4(false);
1417
+ ({ content, upgradeUrl, anchorRef, trackingData }, ref) => {
1418
+ const [isOpen, setIsOpen] = useState5(false);
1050
1419
  useCanvasClickHandler(isOpen, () => setIsOpen(false));
1051
- const toggle = () => setIsOpen((prev) => !prev);
1052
- useImperativeHandle(ref, () => ({ toggle }), []);
1420
+ const toggle = useCallback7(() => {
1421
+ setIsOpen((prev) => {
1422
+ if (!prev) {
1423
+ trackViewPromotion(trackingData);
1424
+ }
1425
+ return !prev;
1426
+ });
1427
+ }, [trackingData]);
1428
+ useImperativeHandle(ref, () => ({ toggle }), [toggle]);
1053
1429
  const handleToggle = (e) => {
1054
1430
  e.stopPropagation();
1055
1431
  toggle();
@@ -1058,19 +1434,20 @@ var InteractionsPromotionChip = forwardRef(
1058
1434
  PromotionPopover,
1059
1435
  {
1060
1436
  open: isOpen,
1061
- title: __7("Interactions", "elementor"),
1437
+ title: __8("Interactions", "elementor"),
1062
1438
  content,
1063
- ctaText: __7("Upgrade now", "elementor"),
1439
+ ctaText: __8("Upgrade now", "elementor"),
1064
1440
  ctaUrl: upgradeUrl,
1065
1441
  anchorRef,
1066
1442
  placement: anchorRef ? "right-start" : void 0,
1067
1443
  onClose: (e) => {
1068
1444
  e.stopPropagation();
1069
1445
  setIsOpen(false);
1070
- }
1446
+ },
1447
+ onCtaClick: () => trackUpgradePromotionClick(trackingData)
1071
1448
  },
1072
1449
  /* @__PURE__ */ React13.createElement(
1073
- Box3,
1450
+ Box2,
1074
1451
  {
1075
1452
  onMouseDown: (e) => e.stopPropagation(),
1076
1453
  onClick: handleToggle,
@@ -1081,7 +1458,6 @@ var InteractionsPromotionChip = forwardRef(
1081
1458
  );
1082
1459
  }
1083
1460
  );
1084
- InteractionsPromotionChip.displayName = "InteractionsPromotionChip";
1085
1461
 
1086
1462
  // src/ui/promotion-select.tsx
1087
1463
  function PromotionSelect({
@@ -1091,10 +1467,11 @@ function PromotionSelect({
1091
1467
  disabledOptions,
1092
1468
  promotionLabel,
1093
1469
  promotionContent,
1094
- upgradeUrl
1470
+ upgradeUrl,
1471
+ trackingData
1095
1472
  }) {
1096
- const promotionRef = useRef4(null);
1097
- const anchorRef = useRef4(null);
1473
+ const promotionRef = useRef3(null);
1474
+ const anchorRef = useRef3(null);
1098
1475
  return /* @__PURE__ */ React14.createElement(
1099
1476
  Select,
1100
1477
  {
@@ -1122,14 +1499,15 @@ function PromotionSelect({
1122
1499
  promotionRef.current?.toggle();
1123
1500
  }
1124
1501
  },
1125
- promotionLabel ?? __8("PRO features", "elementor"),
1502
+ promotionLabel ?? __9("PRO features", "elementor"),
1126
1503
  /* @__PURE__ */ React14.createElement(
1127
1504
  InteractionsPromotionChip,
1128
1505
  {
1129
1506
  content: promotionContent,
1130
1507
  upgradeUrl,
1131
1508
  ref: promotionRef,
1132
- anchorRef
1509
+ anchorRef,
1510
+ trackingData
1133
1511
  }
1134
1512
  )
1135
1513
  ),
@@ -1138,14 +1516,15 @@ function PromotionSelect({
1138
1516
  }
1139
1517
 
1140
1518
  // src/components/controls/easing.tsx
1519
+ var TRACKING_DATA = { target_name: "interactions_easing", location_l2: "interactions" };
1141
1520
  var EASING_OPTIONS = {
1142
- easeIn: __9("Ease In", "elementor"),
1143
- easeInOut: __9("Ease In Out", "elementor"),
1144
- easeOut: __9("Ease Out", "elementor"),
1145
- backIn: __9("Back In", "elementor"),
1146
- backInOut: __9("Back In Out", "elementor"),
1147
- backOut: __9("Back Out", "elementor"),
1148
- linear: __9("Linear", "elementor")
1521
+ easeIn: __10("Ease In", "elementor"),
1522
+ easeInOut: __10("Ease In Out", "elementor"),
1523
+ easeOut: __10("Ease Out", "elementor"),
1524
+ backIn: __10("Back In", "elementor"),
1525
+ backInOut: __10("Back In Out", "elementor"),
1526
+ backOut: __10("Back Out", "elementor"),
1527
+ linear: __10("Linear", "elementor")
1149
1528
  };
1150
1529
  var BASE_EASINGS = ["easeIn"];
1151
1530
  function Easing({}) {
@@ -1161,20 +1540,22 @@ function Easing({}) {
1161
1540
  value: DEFAULT_VALUES.easing,
1162
1541
  baseOptions,
1163
1542
  disabledOptions,
1164
- promotionContent: __9("Upgrade to control the smoothness of the interaction.", "elementor"),
1165
- upgradeUrl: "https://go.elementor.com/go-pro-interactions-easing-modal/"
1543
+ promotionContent: __10("Upgrade to control the smoothness of the interaction.", "elementor"),
1544
+ upgradeUrl: "https://go.elementor.com/go-pro-interactions-easing-modal/",
1545
+ trackingData: TRACKING_DATA
1166
1546
  }
1167
1547
  );
1168
1548
  }
1169
1549
 
1170
1550
  // src/components/controls/effect.tsx
1171
1551
  import * as React16 from "react";
1172
- import { __ as __10 } from "@wordpress/i18n";
1552
+ import { __ as __11 } from "@wordpress/i18n";
1553
+ var TRACKING_DATA2 = { target_name: "interactions_effect", location_l2: "interactions" };
1173
1554
  var EFFECT_OPTIONS = {
1174
- fade: __10("Fade", "elementor"),
1175
- slide: __10("Slide", "elementor"),
1176
- scale: __10("Scale", "elementor"),
1177
- custom: __10("Custom", "elementor")
1555
+ fade: __11("Fade", "elementor"),
1556
+ slide: __11("Slide", "elementor"),
1557
+ scale: __11("Scale", "elementor"),
1558
+ custom: __11("Custom", "elementor")
1178
1559
  };
1179
1560
  var BASE_EFFECTS = ["fade", "slide", "scale"];
1180
1561
  function Effect({ value, onChange }) {
@@ -1191,12 +1572,13 @@ function Effect({ value, onChange }) {
1191
1572
  onChange,
1192
1573
  baseOptions,
1193
1574
  disabledOptions,
1194
- promotionLabel: __10("PRO effects", "elementor"),
1195
- promotionContent: __10(
1575
+ promotionLabel: __11("PRO effects", "elementor"),
1576
+ promotionContent: __11(
1196
1577
  "Upgrade to further customize your animation with opacity, scale, move, rotate and more.",
1197
1578
  "elementor"
1198
1579
  ),
1199
- upgradeUrl: "https://go.elementor.com/go-pro-interactions-custom-effect-modal/"
1580
+ upgradeUrl: "https://go.elementor.com/go-pro-interactions-custom-effect-modal/",
1581
+ trackingData: TRACKING_DATA2
1200
1582
  }
1201
1583
  );
1202
1584
  }
@@ -1204,74 +1586,147 @@ function Effect({ value, onChange }) {
1204
1586
  // src/components/controls/effect-type.tsx
1205
1587
  import * as React17 from "react";
1206
1588
  import { ToggleButtonGroupUi as ToggleButtonGroupUi2 } from "@elementor/editor-controls";
1207
- import { __ as __11 } from "@wordpress/i18n";
1589
+ import { __ as __12 } from "@wordpress/i18n";
1208
1590
  function EffectType({ value, onChange }) {
1209
1591
  const options = [
1210
1592
  {
1211
1593
  value: "in",
1212
- label: __11("In", "elementor"),
1213
- renderContent: () => __11("In", "elementor"),
1594
+ label: __12("In", "elementor"),
1595
+ renderContent: () => __12("In", "elementor"),
1214
1596
  showTooltip: true
1215
1597
  },
1216
1598
  {
1217
1599
  value: "out",
1218
- label: __11("Out", "elementor"),
1219
- renderContent: () => __11("Out", "elementor"),
1600
+ label: __12("Out", "elementor"),
1601
+ renderContent: () => __12("Out", "elementor"),
1220
1602
  showTooltip: true
1221
1603
  }
1222
1604
  ];
1223
1605
  return /* @__PURE__ */ React17.createElement(ToggleButtonGroupUi2, { items: options, exclusive: true, onChange, value });
1224
1606
  }
1225
1607
 
1226
- // src/components/controls/replay.tsx
1227
- import * as React18 from "react";
1608
+ // src/components/controls/repeat.tsx
1609
+ import * as React19 from "react";
1610
+ import { useRef as useRef4 } from "react";
1228
1611
  import { ToggleButtonGroupUi as ToggleButtonGroupUi3 } from "@elementor/editor-controls";
1612
+ import { Number123Icon, RepeatIcon } from "@elementor/icons";
1613
+ import { __ as __13 } from "@wordpress/i18n";
1614
+
1615
+ // src/ui/promotion-overlay-layout.tsx
1616
+ import * as React18 from "react";
1617
+ import { forwardRef as forwardRef2 } from "react";
1618
+ import { Box as Box3 } from "@elementor/ui";
1619
+ var OVERLAY_GRID = "1 / 1";
1620
+ var CHIP_OFFSET = "50%";
1621
+ var PromotionOverlayLayout = forwardRef2(
1622
+ ({ children, promotionChip }, ref) => /* @__PURE__ */ React18.createElement(Box3, { ref, sx: { display: "grid", alignItems: "center" } }, /* @__PURE__ */ React18.createElement(Box3, { sx: { gridArea: OVERLAY_GRID } }, children), /* @__PURE__ */ React18.createElement(Box3, { sx: { gridArea: OVERLAY_GRID, marginInlineEnd: CHIP_OFFSET, justifySelf: "end" } }, promotionChip))
1623
+ );
1624
+
1625
+ // src/components/controls/repeat.tsx
1626
+ var TRACKING_DATA3 = { target_name: "interactions_repeat", location_l2: "interactions" };
1627
+ var REPEAT_OPTIONS = {
1628
+ times: __13("times", "elementor"),
1629
+ loop: __13("loop", "elementor")
1630
+ };
1631
+ var REPEAT_TOOLTIPS = {
1632
+ times: __13("Enable number", "elementor"),
1633
+ loop: __13("Infinite repeat", "elementor")
1634
+ };
1635
+ function Repeat() {
1636
+ const repeatContainerRef = useRef4(null);
1637
+ const options = [
1638
+ {
1639
+ value: REPEAT_OPTIONS.times,
1640
+ disabled: true,
1641
+ label: REPEAT_TOOLTIPS.times,
1642
+ renderContent: ({ size }) => /* @__PURE__ */ React19.createElement(Number123Icon, { fontSize: size }),
1643
+ showTooltip: true
1644
+ },
1645
+ {
1646
+ value: REPEAT_OPTIONS.loop,
1647
+ disabled: true,
1648
+ label: REPEAT_TOOLTIPS.loop,
1649
+ renderContent: ({ size }) => /* @__PURE__ */ React19.createElement(RepeatIcon, { fontSize: size }),
1650
+ showTooltip: true
1651
+ }
1652
+ ];
1653
+ return /* @__PURE__ */ React19.createElement(
1654
+ PromotionOverlayLayout,
1655
+ {
1656
+ ref: repeatContainerRef,
1657
+ promotionChip: /* @__PURE__ */ React19.createElement(
1658
+ InteractionsPromotionChip,
1659
+ {
1660
+ content: __13("Upgrade to control how many times the animation repeats.", "elementor"),
1661
+ upgradeUrl: "https://go.elementor.com/go-pro-interactions-repeat-modal/",
1662
+ anchorRef: repeatContainerRef,
1663
+ trackingData: TRACKING_DATA3
1664
+ }
1665
+ )
1666
+ },
1667
+ /* @__PURE__ */ React19.createElement(ToggleButtonGroupUi3, { items: options, exclusive: true, onChange: () => {
1668
+ }, value: "" })
1669
+ );
1670
+ }
1671
+
1672
+ // src/components/controls/replay.tsx
1673
+ import * as React20 from "react";
1674
+ import { useRef as useRef5 } from "react";
1675
+ import { ToggleButtonGroupUi as ToggleButtonGroupUi4 } from "@elementor/editor-controls";
1229
1676
  import { CheckIcon, MinusIcon } from "@elementor/icons";
1230
- import { Box as Box4 } from "@elementor/ui";
1231
- import { __ as __12 } from "@wordpress/i18n";
1677
+ import { __ as __14 } from "@wordpress/i18n";
1678
+ var TRACKING_DATA4 = { target_name: "interactions_replay", location_l2: "interactions" };
1232
1679
  var REPLAY_OPTIONS = {
1233
- no: __12("No", "elementor"),
1234
- yes: __12("Yes", "elementor")
1680
+ no: __14("No", "elementor"),
1681
+ yes: __14("Yes", "elementor")
1235
1682
  };
1236
1683
  var BASE_REPLAY = ["no"];
1237
- var OVERLAY_GRID = "1 / 1";
1238
- var CHIP_OFFSET = "50%";
1239
- function Replay({ onChange, anchorRef }) {
1684
+ function Replay({ onChange }) {
1685
+ const replayContainerRef = useRef5(null);
1240
1686
  const options = [
1241
1687
  {
1242
1688
  value: false,
1243
1689
  disabled: false,
1244
1690
  label: REPLAY_OPTIONS.no,
1245
- renderContent: ({ size }) => /* @__PURE__ */ React18.createElement(MinusIcon, { fontSize: size }),
1691
+ renderContent: ({ size }) => /* @__PURE__ */ React20.createElement(MinusIcon, { fontSize: size }),
1246
1692
  showTooltip: true
1247
1693
  },
1248
1694
  {
1249
1695
  value: true,
1250
1696
  disabled: true,
1251
1697
  label: REPLAY_OPTIONS.yes,
1252
- renderContent: ({ size }) => /* @__PURE__ */ React18.createElement(CheckIcon, { fontSize: size }),
1698
+ renderContent: ({ size }) => /* @__PURE__ */ React20.createElement(CheckIcon, { fontSize: size }),
1253
1699
  showTooltip: true
1254
1700
  }
1255
1701
  ];
1256
- return /* @__PURE__ */ React18.createElement(Box4, { sx: { display: "grid", alignItems: "center" } }, /* @__PURE__ */ React18.createElement(Box4, { sx: { gridArea: OVERLAY_GRID } }, /* @__PURE__ */ React18.createElement(ToggleButtonGroupUi3, { items: options, exclusive: true, onChange, value: false })), /* @__PURE__ */ React18.createElement(Box4, { sx: { gridArea: OVERLAY_GRID, marginInlineEnd: CHIP_OFFSET, justifySelf: "end" } }, /* @__PURE__ */ React18.createElement(
1257
- InteractionsPromotionChip,
1702
+ return /* @__PURE__ */ React20.createElement(
1703
+ PromotionOverlayLayout,
1258
1704
  {
1259
- content: __12("Upgrade to run the animation every time its trigger occurs.", "elementor"),
1260
- upgradeUrl: "https://go.elementor.com/go-pro-interactions-replay-modal/",
1261
- anchorRef
1262
- }
1263
- )));
1705
+ ref: replayContainerRef,
1706
+ promotionChip: /* @__PURE__ */ React20.createElement(
1707
+ InteractionsPromotionChip,
1708
+ {
1709
+ content: __14("Upgrade to run the animation every time its trigger occurs.", "elementor"),
1710
+ upgradeUrl: "https://go.elementor.com/go-pro-interactions-replay-modal/",
1711
+ anchorRef: replayContainerRef,
1712
+ trackingData: TRACKING_DATA4
1713
+ }
1714
+ )
1715
+ },
1716
+ /* @__PURE__ */ React20.createElement(ToggleButtonGroupUi4, { items: options, exclusive: true, onChange, value: false })
1717
+ );
1264
1718
  }
1265
1719
 
1266
1720
  // src/components/controls/trigger.tsx
1267
- import * as React19 from "react";
1268
- import { __ as __13 } from "@wordpress/i18n";
1721
+ import * as React21 from "react";
1722
+ import { __ as __15 } from "@wordpress/i18n";
1723
+ var TRACKING_DATA5 = { target_name: "interactions_trigger", location_l2: "interactions" };
1269
1724
  var TRIGGER_OPTIONS = {
1270
- load: __13("Page load", "elementor"),
1271
- scrollIn: __13("Scroll into view", "elementor"),
1272
- scrollOn: __13("While scrolling", "elementor"),
1273
- hover: __13("On hover", "elementor"),
1274
- click: __13("On click", "elementor")
1725
+ load: __15("Page load", "elementor"),
1726
+ scrollIn: __15("Scroll into view", "elementor"),
1727
+ scrollOn: __15("While scrolling", "elementor"),
1728
+ hover: __15("On hover", "elementor"),
1729
+ click: __15("On click", "elementor")
1275
1730
  };
1276
1731
  var BASE_TRIGGERS = ["load", "scrollIn"];
1277
1732
  function Trigger({ value, onChange }) {
@@ -1281,22 +1736,23 @@ function Trigger({ value, onChange }) {
1281
1736
  const disabledOptions = Object.fromEntries(
1282
1737
  Object.entries(TRIGGER_OPTIONS).filter(([key]) => !BASE_TRIGGERS.includes(key))
1283
1738
  );
1284
- return /* @__PURE__ */ React19.createElement(
1739
+ return /* @__PURE__ */ React21.createElement(
1285
1740
  PromotionSelect,
1286
1741
  {
1287
1742
  value: value in baseOptions ? value : DEFAULT_VALUES.trigger,
1288
1743
  onChange,
1289
1744
  baseOptions,
1290
1745
  disabledOptions,
1291
- promotionLabel: __13("PRO triggers", "elementor"),
1292
- promotionContent: __13("Upgrade to unlock more interactions triggers.", "elementor"),
1293
- upgradeUrl: "https://go.elementor.com/go-pro-interactions-triggers-modal/"
1746
+ promotionLabel: __15("PRO triggers", "elementor"),
1747
+ promotionContent: __15("Upgrade to unlock more interactions triggers.", "elementor"),
1748
+ upgradeUrl: "https://go.elementor.com/go-pro-interactions-triggers-modal/",
1749
+ trackingData: TRACKING_DATA5
1294
1750
  }
1295
1751
  );
1296
1752
  }
1297
1753
 
1298
1754
  // src/hooks/on-duplicate.ts
1299
- import { getAllDescendants, getContainer } from "@elementor/editor-elements";
1755
+ import { getAllDescendants, getContainer as getContainer2 } from "@elementor/editor-elements";
1300
1756
  import { registerDataHook } from "@elementor/editor-v1-adapters";
1301
1757
  function initCleanInteractionIdsOnDuplicate() {
1302
1758
  registerDataHook("after", "document/elements/duplicate", (_args, result) => {
@@ -1307,7 +1763,7 @@ function initCleanInteractionIdsOnDuplicate() {
1307
1763
  });
1308
1764
  }
1309
1765
  function cleanInteractionIdsRecursive(elementId) {
1310
- const container = getContainer(elementId);
1766
+ const container = getContainer2(elementId);
1311
1767
  if (!container) {
1312
1768
  return;
1313
1769
  }
@@ -1316,7 +1772,7 @@ function cleanInteractionIdsRecursive(elementId) {
1316
1772
  });
1317
1773
  }
1318
1774
  function cleanInteractionIds(elementId) {
1319
- const container = getContainer(elementId);
1775
+ const container = getContainer2(elementId);
1320
1776
  if (!container) {
1321
1777
  return;
1322
1778
  }
@@ -1333,12 +1789,6 @@ function cleanInteractionIds(elementId) {
1333
1789
  container.model.set("interactions", updatedInteractions);
1334
1790
  }
1335
1791
 
1336
- // src/mcp/index.ts
1337
- import { getMCPByDomain } from "@elementor/editor-mcp";
1338
-
1339
- // src/mcp/constants.ts
1340
- var MAX_INTERACTIONS_PER_ELEMENT = 5;
1341
-
1342
1792
  // src/mcp/resources/interactions-schema-resource.ts
1343
1793
  import { isProActive } from "@elementor/utils";
1344
1794
 
@@ -1359,7 +1809,7 @@ var baseSchema = {
1359
1809
  var proSchema = {
1360
1810
  trigger: z.enum(["load", "scrollIn", "scrollOut", "scrollOn", "hover", "click"]).optional().describe("Event that triggers the animation"),
1361
1811
  effect: z.enum(["fade", "slide", "scale", "custom"]).optional().describe("Animation effect type"),
1362
- customEffect: z.object({
1812
+ customEffects: z.object({
1363
1813
  keyframes: z.array(
1364
1814
  z.object({
1365
1815
  stop: z.number().describe("The stop of the keyframe in percent, can be either 0 or 100"),
@@ -1415,13 +1865,77 @@ var initInteractionsSchemaResource = (reg) => {
1415
1865
  };
1416
1866
 
1417
1867
  // src/mcp/tools/manage-element-interaction-tool.ts
1418
- import { updateElementInteractions as updateElementInteractions2 } from "@elementor/editor-elements";
1868
+ import { updateElementInteractions as updateElementInteractions3 } from "@elementor/editor-elements";
1419
1869
  import { z as z2 } from "@elementor/schema";
1420
1870
  import { isProActive as isProActive2 } from "@elementor/utils";
1871
+
1872
+ // src/mcp/constants.ts
1873
+ var MAX_INTERACTIONS_PER_ELEMENT = 5;
1874
+ 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.
1875
+ ** IMPORTANT **
1876
+ Use the "interactions-schema" resource to get the schema of the interactions.
1877
+ Actions:
1878
+ - get: Read the current interactions on the element.
1879
+ - add: Add a new interaction (max ${MAX_INTERACTIONS_PER_ELEMENT} per element).
1880
+ - update: Update an existing interaction by its interactionId.
1881
+ - delete: Remove a specific interaction by its interactionId.
1882
+ - clear: Remove all interactions from the element.
1883
+
1884
+ For add/update, provide: trigger, effect, effectType, direction (required for slide effect), duration, delay, easing.
1885
+ Use excludedBreakpoints to disable the animation on specific responsive breakpoints (e.g. ["mobile", "tablet"]).
1886
+ Example Get Request:
1887
+ {
1888
+ "elementId": "123",
1889
+ "action": "get",
1890
+ "interactionId": "123",
1891
+ "animationData": {
1892
+ "trigger": "click",
1893
+ "effect": "fade",
1894
+ }
1895
+ }
1896
+ Example Add Request:
1897
+ {
1898
+ "elementId": "123",
1899
+ "action": "add",
1900
+ "animationData": {
1901
+ "effectType": "in",
1902
+ "direction": "top",
1903
+ "trigger": "click",
1904
+ "effect": "fade",
1905
+ "duration": 1000,
1906
+ "delay": 0,
1907
+ "easing": "easeIn",
1908
+ "excludedBreakpoints": ["mobile", "tablet"],
1909
+ }
1910
+ }
1911
+ Example Update Request:
1912
+ {
1913
+ "elementId": "123",
1914
+ "action": "update",
1915
+ "interactionId": "123",
1916
+ "animationData": {
1917
+ "trigger": "click",
1918
+ "effect": "fade",
1919
+ }
1920
+ }
1921
+ Example Delete Request:
1922
+ {
1923
+ "elementId": "123",
1924
+ "action": "delete",
1925
+ "interactionId": "123",
1926
+ }
1927
+ Example Clear Request:
1928
+ {
1929
+ "elementId": "123",
1930
+ "action": "clear",
1931
+ }`;
1932
+
1933
+ // src/mcp/tools/manage-element-interaction-tool.ts
1421
1934
  var EMPTY_INTERACTIONS = {
1422
1935
  version: 1,
1423
1936
  items: []
1424
1937
  };
1938
+ var EFFECTS_WITHOUT_TYPE = ["custom"];
1425
1939
  var initManageElementInteractionTool = (reg) => {
1426
1940
  const { addTool } = reg;
1427
1941
  const extendedSchema = isProActive2() ? { ...baseSchema, ...proSchema } : baseSchema;
@@ -1448,16 +1962,36 @@ var initManageElementInteractionTool = (reg) => {
1448
1962
  },
1449
1963
  handler: (input) => {
1450
1964
  const { elementId, action, interactionId, ...animationData } = input;
1965
+ const { effectType, ...restAnimationData } = animationData;
1966
+ const effect = restAnimationData.effect;
1967
+ const resolvedType = effectType ?? (effect && !EFFECTS_WITHOUT_TYPE.includes(effect) ? "in" : void 0);
1451
1968
  const allInteractions = interactionsRepository.all();
1452
1969
  const elementData = allInteractions.find((data) => data.elementId === elementId);
1453
1970
  const currentInteractions = elementData?.interactions ?? EMPTY_INTERACTIONS;
1454
1971
  if (action === "get") {
1972
+ const summary = currentInteractions.items.map((item) => {
1973
+ const { value } = item;
1974
+ const animValue = value.animation.value;
1975
+ const timingValue = animValue.timing_config.value;
1976
+ const configValue = animValue.config.value;
1977
+ return {
1978
+ id: extractString(value.interaction_id),
1979
+ trigger: extractString(value.trigger),
1980
+ effect: extractString(animValue.effect),
1981
+ effectType: extractString(animValue.type),
1982
+ direction: extractString(animValue.direction),
1983
+ duration: extractSize(timingValue.duration),
1984
+ delay: extractSize(timingValue.delay),
1985
+ easing: extractString(configValue.easing),
1986
+ excludedBreakpoints: extractExcludedBreakpoints(value.breakpoints)
1987
+ };
1988
+ });
1455
1989
  return {
1456
1990
  success: true,
1457
1991
  elementId,
1458
1992
  action,
1459
- interactions: currentInteractions.items,
1460
- count: currentInteractions.items.length
1993
+ interactions: summary,
1994
+ count: summary.length
1461
1995
  };
1462
1996
  }
1463
1997
  let updatedItems = [...currentInteractions.items];
@@ -1470,7 +2004,8 @@ var initManageElementInteractionTool = (reg) => {
1470
2004
  }
1471
2005
  const newItem = createInteractionItem({
1472
2006
  interactionId: generateTempInteractionId(),
1473
- ...animationData
2007
+ ...restAnimationData,
2008
+ type: resolvedType
1474
2009
  });
1475
2010
  updatedItems = [...updatedItems, newItem];
1476
2011
  break;
@@ -1489,7 +2024,8 @@ var initManageElementInteractionTool = (reg) => {
1489
2024
  }
1490
2025
  const updatedItem = createInteractionItem({
1491
2026
  interactionId,
1492
- ...animationData
2027
+ ...restAnimationData,
2028
+ type: resolvedType
1493
2029
  });
1494
2030
  updatedItems = [
1495
2031
  ...updatedItems.slice(0, itemIndex),
@@ -1523,7 +2059,7 @@ var initManageElementInteractionTool = (reg) => {
1523
2059
  items: updatedItems
1524
2060
  };
1525
2061
  try {
1526
- updateElementInteractions2({ elementId, interactions: updatedInteractions });
2062
+ updateElementInteractions3({ elementId, interactions: updatedInteractions });
1527
2063
  } catch (error) {
1528
2064
  throw new Error(
1529
2065
  `Failed to update interactions for element "${elementId}": ${error instanceof Error ? error.message : "Unknown error"}`
@@ -1540,73 +2076,18 @@ var initManageElementInteractionTool = (reg) => {
1540
2076
  };
1541
2077
 
1542
2078
  // src/mcp/index.ts
1543
- var initMcpInteractions = () => {
1544
- const reg = getMCPByDomain("interactions", {
1545
- instructions: `
1546
- 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.
1547
- ** IMPORTANT **
1548
- Use the "interactions-schema" resource to get the schema of the interactions.
1549
- Actions:
1550
- - get: Read the current interactions on the element.
1551
- - add: Add a new interaction (max ${MAX_INTERACTIONS_PER_ELEMENT} per element).
1552
- - update: Update an existing interaction by its interactionId.
1553
- - delete: Remove a specific interaction by its interactionId.
1554
- - clear: Remove all interactions from the element.
1555
-
1556
- For add/update, provide: trigger, effect, effectType, direction (required for slide effect), duration, delay, easing.
1557
- Use excludedBreakpoints to disable the animation on specific responsive breakpoints (e.g. ["mobile", "tablet"]).
1558
- Example Get Request:
1559
- {
1560
- "elementId": "123",
1561
- "action": "get",
1562
- "interactionId": "123",
1563
- "animationData": {
1564
- "trigger": "click",
1565
- "effect": "fade",
1566
- }
1567
- }
1568
- Example Add Request:
1569
- {
1570
- "elementId": "123",
1571
- "action": "add",
1572
- "animationData": {
1573
- "effectType": "in",
1574
- "direction": "top",
1575
- "trigger": "click",
1576
- "effect": "fade",
1577
- "duration": 1000,
1578
- "delay": 0,
1579
- "easing": "easeIn",
1580
- "excludedBreakpoints": ["mobile", "tablet"],
1581
- }
1582
- }
1583
- Example Update Request:
1584
- {
1585
- "elementId": "123",
1586
- "action": "update",
1587
- "interactionId": "123",
1588
- "animationData": {
1589
- "trigger": "click",
1590
- "effect": "fade",
1591
- }
1592
- }
1593
- Example Delete Request:
1594
- {
1595
- "elementId": "123",
1596
- "action": "delete",
1597
- "interactionId": "123",
1598
- }
1599
- Example Clear Request:
1600
- {
1601
- "elementId": "123",
1602
- "action": "clear",
1603
- }
1604
- `
1605
- });
1606
- reg.waitForReady().then(() => {
1607
- initInteractionsSchemaResource(reg);
1608
- initManageElementInteractionTool(reg);
1609
- });
2079
+ var initMcpInteractions = (reg) => {
2080
+ const { setMCPDescription } = reg;
2081
+ setMCPDescription(
2082
+ `Everything related to V4 ( Atomic ) interactions.
2083
+ # Interactions
2084
+ - Create/update/delete interactions
2085
+ - Get list of interactions
2086
+ - Get details of an interaction
2087
+ `
2088
+ );
2089
+ initInteractionsSchemaResource(reg);
2090
+ initManageElementInteractionTool(reg);
1610
2091
  };
1611
2092
 
1612
2093
  // src/init.ts
@@ -1614,6 +2095,7 @@ function init() {
1614
2095
  try {
1615
2096
  interactionsRepository.register(documentElementsInteractionsProvider);
1616
2097
  initCleanInteractionIdsOnDuplicate();
2098
+ initPasteInteractionsCommand();
1617
2099
  registerInteractionsControl({
1618
2100
  type: "trigger",
1619
2101
  component: Trigger,
@@ -1627,7 +2109,7 @@ function init() {
1627
2109
  registerInteractionsControl({
1628
2110
  type: "replay",
1629
2111
  component: Replay,
1630
- options: ["true", "false"]
2112
+ options: ["no"]
1631
2113
  });
1632
2114
  registerInteractionsControl({
1633
2115
  type: "effectType",
@@ -1644,7 +2126,11 @@ function init() {
1644
2126
  component: Effect,
1645
2127
  options: ["fade", "slide", "scale"]
1646
2128
  });
1647
- initMcpInteractions();
2129
+ registerInteractionsControl({
2130
+ type: "repeat",
2131
+ component: Repeat
2132
+ });
2133
+ initMcpInteractions(getMCPByDomain("interactions", { instructions: EDITOR_INTERACTIONS_MCP_INSTRUCTIONS }));
1648
2134
  } catch (error) {
1649
2135
  throw error;
1650
2136
  }
@@ -1659,12 +2145,37 @@ export {
1659
2145
  ELEMENTS_INTERACTIONS_PROVIDER_KEY_PREFIX,
1660
2146
  EmptyState,
1661
2147
  InteractionsTab,
2148
+ REPEAT_OPTIONS,
2149
+ REPEAT_TOOLTIPS,
1662
2150
  REPLAY_OPTIONS,
1663
2151
  TRIGGER_OPTIONS,
2152
+ buildDisplayLabel,
2153
+ convertTimeUnit,
2154
+ createAnimationPreset,
2155
+ createBoolean,
2156
+ createConfig,
2157
+ createDefaultInteractionItem,
2158
+ createDefaultInteractions,
2159
+ createExcludedBreakpoints,
2160
+ createInteractionBreakpoints,
2161
+ createInteractionItem,
1664
2162
  createInteractionsProvider,
2163
+ createNumber,
2164
+ createString,
2165
+ createTimingConfig,
2166
+ extractBoolean,
2167
+ extractExcludedBreakpoints,
2168
+ extractSize,
2169
+ extractString,
2170
+ formatSizeValue,
2171
+ generateTempInteractionId,
1665
2172
  getInteractionsConfig,
1666
2173
  init,
1667
2174
  interactionsRepository,
1668
- registerInteractionsControl
2175
+ isTempId,
2176
+ parseSizeValue,
2177
+ registerInteractionsControl,
2178
+ resolveDirection,
2179
+ useElementInteractions
1669
2180
  };
1670
2181
  //# sourceMappingURL=index.mjs.map