@elementor/editor-interactions 4.0.0-manual → 4.1.0-684

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elementor/editor-interactions",
3
- "version": "4.0.0-manual",
3
+ "version": "4.1.0-684",
4
4
  "private": false,
5
5
  "author": "Elementor Team",
6
6
  "homepage": "https://elementor.com/",
@@ -39,18 +39,19 @@
39
39
  "dev": "tsup --config=../../tsup.dev.ts"
40
40
  },
41
41
  "dependencies": {
42
- "@elementor/editor-controls": "4.0.0-manual",
43
- "@elementor/editor-elements": "4.0.0-manual",
44
- "@elementor/editor-mcp": "4.0.0-manual",
45
- "@elementor/editor-props": "4.0.0-manual",
46
- "@elementor/editor-responsive": "4.0.0-manual",
47
- "@elementor/editor-ui": "4.0.0-manual",
48
- "@elementor/editor-v1-adapters": "4.0.0-manual",
42
+ "@elementor/editor-controls": "4.1.0-684",
43
+ "@elementor/editor-elements": "4.1.0-684",
44
+ "@elementor/editor-mcp": "4.1.0-684",
45
+ "@elementor/editor-props": "4.1.0-684",
46
+ "@elementor/editor-responsive": "4.1.0-684",
47
+ "@elementor/editor-ui": "4.1.0-684",
48
+ "@elementor/editor-v1-adapters": "4.1.0-684",
49
49
  "@elementor/icons": "^1.68.0",
50
- "@elementor/schema": "4.0.0-manual",
51
- "@elementor/session": "4.0.0-manual",
50
+ "@elementor/schema": "4.1.0-684",
51
+ "@elementor/session": "4.1.0-684",
52
52
  "@elementor/ui": "1.36.17",
53
- "@elementor/utils": "4.0.0-manual",
53
+ "@elementor/utils": "4.1.0-684",
54
+ "@elementor/events": "4.1.0-684",
54
55
  "@wordpress/i18n": "^5.13.0"
55
56
  },
56
57
  "peerDependencies": {
@@ -0,0 +1,11 @@
1
+ import type { V1ElementModelProps } from '@elementor/editor-elements';
2
+
3
+ export function getClipboardElements( storageKey: string = 'clipboard' ): V1ElementModelProps[] | undefined {
4
+ try {
5
+ const storedData = JSON.parse( localStorage.getItem( 'elementor' ) ?? '{}' );
6
+
7
+ return storedData[ storageKey ]?.elements as V1ElementModelProps[] | undefined;
8
+ } catch {
9
+ return undefined;
10
+ }
11
+ }
@@ -0,0 +1,136 @@
1
+ import {
2
+ getContainer,
3
+ getElementInteractions,
4
+ getElementLabel,
5
+ getWidgetsCache,
6
+ updateElementInteractions,
7
+ type V1Element,
8
+ type V1ElementModelProps,
9
+ } from '@elementor/editor-elements';
10
+ import {
11
+ __privateListenTo as listenTo,
12
+ type CommandEvent,
13
+ commandStartEvent,
14
+ undoable,
15
+ } from '@elementor/editor-v1-adapters';
16
+ import { __ } from '@wordpress/i18n';
17
+
18
+ import type { ElementInteractions } from '../types';
19
+ import { createString } from '../utils/prop-value-utils';
20
+ import { generateTempInteractionId } from '../utils/temp-id-utils';
21
+ import { getClipboardElements } from './get-clipboard-elements';
22
+
23
+ function isAtomicContainer( container: V1Element ): boolean {
24
+ const type = container?.model.get( 'widgetType' ) || container?.model.get( 'elType' );
25
+ const widgetsCache = getWidgetsCache();
26
+ const elementConfig = widgetsCache?.[ type ];
27
+
28
+ return Boolean( elementConfig?.atomic_props_schema );
29
+ }
30
+
31
+ type PasteInteractionsCommandArgs = {
32
+ container?: V1Element;
33
+ containers?: V1Element[];
34
+ storageKey?: string;
35
+ };
36
+
37
+ type PasteInteractionsPayload = {
38
+ containers: V1Element[];
39
+ newInteractions: ElementInteractions;
40
+ };
41
+
42
+ function getTitleForContainers( containers: V1Element[] ): string {
43
+ return containers.length > 1 ? __( 'Elements', 'elementor' ) : getElementLabel( containers[ 0 ].id );
44
+ }
45
+
46
+ function normalizeClipboardInteractions( raw: V1ElementModelProps[ 'interactions' ] ): ElementInteractions | null {
47
+ if ( ! raw ) {
48
+ return null;
49
+ }
50
+
51
+ const parsed: ElementInteractions = typeof raw === 'string' ? ( JSON.parse( raw ) as ElementInteractions ) : raw;
52
+
53
+ if ( ! parsed?.items?.length ) {
54
+ return null;
55
+ }
56
+
57
+ return { version: parsed.version ?? 1, items: parsed.items };
58
+ }
59
+
60
+ function regenerateInteractionIds( interactions: ElementInteractions ): ElementInteractions {
61
+ const cloned = structuredClone( interactions ) as ElementInteractions;
62
+
63
+ cloned.items?.forEach( ( item ) => {
64
+ if ( item.$$type === 'interaction-item' && item.value ) {
65
+ item.value.interaction_id = createString( generateTempInteractionId() );
66
+ }
67
+ } );
68
+
69
+ return cloned;
70
+ }
71
+
72
+ export function initPasteInteractionsCommand() {
73
+ const undoablePasteInteractions = undoable(
74
+ {
75
+ do: ( { containers, newInteractions }: PasteInteractionsPayload ) => {
76
+ const pasted = regenerateInteractionIds( newInteractions );
77
+
78
+ return containers.map( ( container ) => {
79
+ const elementId = container.id;
80
+ const previous = getElementInteractions( elementId );
81
+
82
+ updateElementInteractions( {
83
+ elementId,
84
+ interactions: pasted,
85
+ } );
86
+
87
+ return { elementId, previous: previous ?? { version: 1, items: [] } };
88
+ } );
89
+ },
90
+ undo: ( _: PasteInteractionsPayload, revertData ) => {
91
+ revertData.forEach( ( { elementId, previous } ) => {
92
+ updateElementInteractions( {
93
+ elementId,
94
+ interactions: previous.items?.length ? previous : undefined,
95
+ } );
96
+ } );
97
+ },
98
+ },
99
+ {
100
+ title: ( { containers } ) => getTitleForContainers( containers ),
101
+ subtitle: __( 'Interactions Pasted', 'elementor' ),
102
+ }
103
+ );
104
+
105
+ listenTo( commandStartEvent( 'document/elements/paste-interactions' ), ( e ) => {
106
+ const args = ( e as CommandEvent ).args as PasteInteractionsCommandArgs;
107
+ const containers = args.containers ?? ( args.container ? [ args.container ] : [] );
108
+ const storageKey = args.storageKey ?? 'clipboard';
109
+
110
+ if ( ! containers.length ) {
111
+ return;
112
+ }
113
+
114
+ const clipboardElements = getClipboardElements( storageKey );
115
+ const [ clipboardElement ] = clipboardElements ?? [];
116
+
117
+ if ( ! clipboardElement ) {
118
+ return;
119
+ }
120
+
121
+ const newInteractions = normalizeClipboardInteractions( clipboardElement.interactions );
122
+
123
+ if ( ! newInteractions ) {
124
+ return;
125
+ }
126
+
127
+ const existingContainers = containers.filter( ( c ) => getContainer( c.id ) ) as V1Element[];
128
+ const validContainers = existingContainers.filter( isAtomicContainer );
129
+
130
+ if ( ! validContainers.length ) {
131
+ return;
132
+ }
133
+
134
+ undoablePasteInteractions( { containers: validContainers, newInteractions } );
135
+ } );
136
+ }
@@ -5,6 +5,8 @@ import { type FieldProps } from '../../types';
5
5
  import { PromotionSelect } from '../../ui/promotion-select';
6
6
  import { DEFAULT_VALUES } from '../interaction-details';
7
7
 
8
+ const TRACKING_DATA = { target_name: 'interactions_easing', location_l2: 'interactions' } as const;
9
+
8
10
  export const EASING_OPTIONS = {
9
11
  easeIn: __( 'Ease In', 'elementor' ),
10
12
  easeInOut: __( 'Ease In Out', 'elementor' ),
@@ -33,6 +35,7 @@ export function Easing( {}: FieldProps ) {
33
35
  disabledOptions={ disabledOptions }
34
36
  promotionContent={ __( 'Upgrade to control the smoothness of the interaction.', 'elementor' ) }
35
37
  upgradeUrl="https://go.elementor.com/go-pro-interactions-easing-modal/"
38
+ trackingData={ TRACKING_DATA }
36
39
  />
37
40
  );
38
41
  }
@@ -5,6 +5,8 @@ import { type FieldProps } from '../../types';
5
5
  import { PromotionSelect } from '../../ui/promotion-select';
6
6
  import { DEFAULT_VALUES } from '../interaction-details';
7
7
 
8
+ const TRACKING_DATA = { target_name: 'interactions_effect', location_l2: 'interactions' } as const;
9
+
8
10
  export const EFFECT_OPTIONS = {
9
11
  fade: __( 'Fade', 'elementor' ),
10
12
  slide: __( 'Slide', 'elementor' ),
@@ -35,6 +37,7 @@ export function Effect( { value, onChange }: FieldProps ) {
35
37
  'elementor'
36
38
  ) }
37
39
  upgradeUrl="https://go.elementor.com/go-pro-interactions-custom-effect-modal/"
40
+ trackingData={ TRACKING_DATA }
38
41
  />
39
42
  );
40
43
  }
@@ -7,6 +7,8 @@ import { __ } from '@wordpress/i18n';
7
7
  import { type ReplayFieldProps } from '../../types';
8
8
  import { InteractionsPromotionChip } from '../../ui/interactions-promotion-chip';
9
9
 
10
+ const TRACKING_DATA = { target_name: 'interactions_replay', location_l2: 'interactions' } as const;
11
+
10
12
  export const REPLAY_OPTIONS = {
11
13
  no: __( 'No', 'elementor' ),
12
14
  yes: __( 'Yes', 'elementor' ),
@@ -45,6 +47,7 @@ export function Replay( { onChange, anchorRef }: ReplayFieldProps ) {
45
47
  content={ __( 'Upgrade to run the animation every time its trigger occurs.', 'elementor' ) }
46
48
  upgradeUrl={ 'https://go.elementor.com/go-pro-interactions-replay-modal/' }
47
49
  anchorRef={ anchorRef }
50
+ trackingData={ TRACKING_DATA }
48
51
  />
49
52
  </Box>
50
53
  </Box>
@@ -5,6 +5,8 @@ import { type FieldProps } from '../../types';
5
5
  import { PromotionSelect } from '../../ui/promotion-select';
6
6
  import { DEFAULT_VALUES } from '../interaction-details';
7
7
 
8
+ const TRACKING_DATA = { target_name: 'interactions_trigger', location_l2: 'interactions' } as const;
9
+
8
10
  export const TRIGGER_OPTIONS = {
9
11
  load: __( 'Page load', 'elementor' ),
10
12
  scrollIn: __( 'Scroll into view', 'elementor' ),
@@ -33,6 +35,7 @@ export function Trigger( { value, onChange }: FieldProps ) {
33
35
  promotionLabel={ __( 'PRO triggers', 'elementor' ) }
34
36
  promotionContent={ __( 'Upgrade to unlock more interactions triggers.', 'elementor' ) }
35
37
  upgradeUrl="https://go.elementor.com/go-pro-interactions-triggers-modal/"
38
+ trackingData={ TRACKING_DATA }
36
39
  />
37
40
  );
38
41
  }
@@ -35,6 +35,8 @@ export const DEFAULT_VALUES = {
35
35
  replay: false,
36
36
  easing: 'easeIn',
37
37
  relativeTo: 'viewport',
38
+ repeat: '',
39
+ times: 1,
38
40
  start: 85,
39
41
  end: 15,
40
42
  };
@@ -53,7 +55,9 @@ type InteractionsControlType =
53
55
  | 'relativeTo'
54
56
  | 'start'
55
57
  | 'end'
56
- | 'customEffects';
58
+ | 'customEffects'
59
+ | 'repeat'
60
+ | 'times';
57
61
 
58
62
  type InteractionValues = {
59
63
  trigger: string;
@@ -68,6 +72,8 @@ type InteractionValues = {
68
72
  start: SizeStringValue;
69
73
  end: SizeStringValue;
70
74
  customEffects?: PropValue;
75
+ repeat: string;
76
+ times: number;
71
77
  };
72
78
 
73
79
  type ControlVisibilityConfig = {
@@ -82,6 +88,8 @@ const controlVisibilityConfig: ControlVisibilityConfig = {
82
88
  relativeTo: ( values ) => values.trigger === 'scrollOn',
83
89
  start: ( values ) => values.trigger === 'scrollOn',
84
90
  end: ( values ) => values.trigger === 'scrollOn',
91
+ repeat: ( values ) => values.trigger !== 'scrollOn',
92
+ times: ( values ) => values.trigger !== 'scrollOn' && values.repeat === 'times',
85
93
 
86
94
  duration: ( values ) => {
87
95
  const isRelativeToVisible = values.trigger === 'scrollOn';
@@ -93,6 +101,14 @@ const controlVisibilityConfig: ControlVisibilityConfig = {
93
101
  },
94
102
  };
95
103
 
104
+ function normalizeTimesValue( value: unknown, fallback: number ): number {
105
+ const numericValue = Number( value );
106
+ if ( ! Number.isFinite( numericValue ) ) {
107
+ return fallback;
108
+ }
109
+ return Math.max( 1, Math.floor( numericValue ) );
110
+ }
111
+
96
112
  function useControlComponent( controlName: InteractionsControlType, isVisible: boolean = true ) {
97
113
  return useMemo( () => {
98
114
  if ( ! isVisible ) {
@@ -113,6 +129,9 @@ export const InteractionDetails = ( { interaction, onChange, onPlayInteraction }
113
129
  const replay = extractBoolean( interaction.animation.value.config?.value.replay, DEFAULT_VALUES.replay );
114
130
  const easing = extractString( interaction.animation.value.config?.value.easing, DEFAULT_VALUES.easing );
115
131
  const relativeTo = extractString( interaction.animation.value.config?.value.relativeTo, DEFAULT_VALUES.relativeTo );
132
+ const configValue = interaction.animation.value.config?.value;
133
+ const repeat = extractString( configValue?.repeat, DEFAULT_VALUES.repeat );
134
+ const times = normalizeTimesValue( configValue?.times?.value, DEFAULT_VALUES.times );
116
135
 
117
136
  const start = extractSize( interaction.animation.value.config?.value.start, DEFAULT_VALUES.start );
118
137
  const end = extractSize( interaction.animation.value.config?.value.end, DEFAULT_VALUES.end );
@@ -127,6 +146,8 @@ export const InteractionDetails = ( { interaction, onChange, onPlayInteraction }
127
146
  easing,
128
147
  replay,
129
148
  relativeTo,
149
+ repeat,
150
+ times,
130
151
  start,
131
152
  end,
132
153
  customEffects,
@@ -151,6 +172,14 @@ export const InteractionDetails = ( { interaction, onChange, onPlayInteraction }
151
172
  controlVisibilityConfig.effectType( interactionValues )
152
173
  );
153
174
  const DirectionControl = useControlComponent( 'direction', controlVisibilityConfig.direction( interactionValues ) );
175
+ const RepeatControl = useControlComponent(
176
+ 'repeat',
177
+ controlVisibilityConfig.repeat( interactionValues )
178
+ ) as ComponentType< FieldProps< string > >;
179
+ const TimesControl = useControlComponent(
180
+ 'times',
181
+ controlVisibilityConfig.times( interactionValues )
182
+ ) as ComponentType< FieldProps< number > >;
154
183
  const EasingControl = useControlComponent( 'easing' );
155
184
 
156
185
  const containerRef = useRef< HTMLDivElement >( null );
@@ -166,6 +195,8 @@ export const InteractionDetails = ( { interaction, onChange, onPlayInteraction }
166
195
  replay: boolean;
167
196
  easing?: string;
168
197
  relativeTo: string;
198
+ repeat: string;
199
+ times?: number;
169
200
  start: SizeStringValue;
170
201
  end: SizeStringValue;
171
202
  customEffects?: PropValue;
@@ -192,6 +223,8 @@ export const InteractionDetails = ( { interaction, onChange, onPlayInteraction }
192
223
  replay: updates.replay ?? replay,
193
224
  easing: updates.easing ?? easing,
194
225
  relativeTo: updates.relativeTo ?? relativeTo,
226
+ repeat: updates.repeat ?? repeat,
227
+ times: updates.times ?? times,
195
228
  start: updates.start ?? start,
196
229
  end: updates.end ?? end,
197
230
  customEffects: updates.customEffects ?? customEffects,
@@ -266,6 +299,25 @@ export const InteractionDetails = ( { interaction, onChange, onPlayInteraction }
266
299
  </Field>
267
300
  ) }
268
301
 
302
+ { RepeatControl && (
303
+ <Field label={ __( 'Repeat', 'elementor' ) }>
304
+ <RepeatControl value={ repeat } onChange={ ( v ) => updateInteraction( { repeat: v } ) } />
305
+ </Field>
306
+ ) }
307
+
308
+ { TimesControl && (
309
+ <Field label={ __( 'Times', 'elementor' ) }>
310
+ <TimesControl
311
+ value={ times }
312
+ onChange={ ( v ) =>
313
+ updateInteraction( {
314
+ times: normalizeTimesValue( v, DEFAULT_VALUES.times ),
315
+ } )
316
+ }
317
+ />
318
+ </Field>
319
+ ) }
320
+
269
321
  { controlVisibilityConfig.duration( interactionValues ) && (
270
322
  <Field label={ __( 'Duration', 'elementor' ) }>
271
323
  <TimeFrameIndicator
@@ -1,13 +1,15 @@
1
1
  import * as React from 'react';
2
2
  import { useCallback, useEffect, useMemo, useRef } from 'react';
3
- import { Repeater } from '@elementor/editor-controls';
3
+ import { Repeater, type SetRepeaterValuesMeta } from '@elementor/editor-controls';
4
4
  import { InfoCircleFilledIcon, PlayerPlayIcon } from '@elementor/icons';
5
5
  import { Alert, AlertTitle, Box, IconButton, Tooltip } from '@elementor/ui';
6
6
  import { __ } from '@wordpress/i18n';
7
7
 
8
+ import { useInteractionsContext } from '../contexts/interactions-context';
8
9
  import { InteractionItemContextProvider } from '../contexts/interactions-item-context';
9
10
  import type { ElementInteractions, InteractionItemPropValue, InteractionItemValue } from '../types';
10
11
  import { buildDisplayLabel, createDefaultInteractionItem, extractString } from '../utils/prop-value-utils';
12
+ import { trackInteractionCreated } from '../utils/tracking';
11
13
  import { InteractionsListItem } from './interactions-list-item';
12
14
  export const MAX_NUMBER_OF_INTERACTIONS = 5;
13
15
 
@@ -20,6 +22,7 @@ export type InteractionListProps = {
20
22
 
21
23
  export function InteractionsList( props: InteractionListProps ) {
22
24
  const { interactions, onSelectInteractions, onPlayInteraction, triggerCreateOnShowEmpty } = props;
25
+ const { elementId } = useInteractionsContext();
23
26
 
24
27
  const hasInitializedRef = useRef( false );
25
28
 
@@ -62,13 +65,23 @@ export function InteractionsList( props: InteractionListProps ) {
62
65
  ) : undefined;
63
66
 
64
67
  const handleRepeaterChange = useCallback(
65
- ( newItems: ElementInteractions[ 'items' ] ) => {
68
+ (
69
+ newItems: ElementInteractions[ 'items' ],
70
+ _: unknown,
71
+ meta?: SetRepeaterValuesMeta< InteractionItemPropValue >
72
+ ) => {
66
73
  handleUpdateInteractions( {
67
74
  ...interactions,
68
75
  items: newItems,
69
76
  } );
77
+ if ( meta?.action?.type === 'add' ) {
78
+ const addedItem = meta.action.payload[ 0 ]?.item;
79
+ if ( addedItem ) {
80
+ trackInteractionCreated( elementId, addedItem );
81
+ }
82
+ }
70
83
  },
71
- [ interactions, handleUpdateInteractions ]
84
+ [ interactions, handleUpdateInteractions, elementId ]
72
85
  );
73
86
 
74
87
  const handleInteractionChange = useCallback(
@@ -1,12 +1,14 @@
1
1
  import * as React from 'react';
2
2
  import { useCallback, useState } from 'react';
3
- import { useElementInteractions } from '@elementor/editor-elements';
4
3
  import { SessionStorageProvider } from '@elementor/session';
5
4
  import { Stack } from '@elementor/ui';
6
5
 
7
6
  import { InteractionsProvider, useInteractionsContext } from '../contexts/interactions-context';
8
7
  import { PopupStateProvider } from '../contexts/popup-state-context';
8
+ import { useElementInteractions } from '../hooks/use-element-interactions';
9
9
  import type { ElementInteractions } from '../types';
10
+ import { createDefaultInteractionItem } from '../utils/prop-value-utils';
11
+ import { trackInteractionCreated } from '../utils/tracking';
10
12
  import { EmptyState } from './empty-state';
11
13
  import { InteractionsList } from './interactions-list';
12
14
 
@@ -33,6 +35,7 @@ function InteractionsTabContent( { elementId }: { elementId: string } ) {
33
35
  <EmptyState
34
36
  onCreateInteraction={ () => {
35
37
  firstInteractionState[ 1 ]( true );
38
+ trackInteractionCreated( elementId, createDefaultInteractionItem() );
36
39
  } }
37
40
  />
38
41
  ) }
@@ -4,10 +4,12 @@ import {
4
4
  type ElementInteractions,
5
5
  playElementInteractions,
6
6
  updateElementInteractions,
7
- useElementInteractions,
8
7
  } from '@elementor/editor-elements';
9
8
 
9
+ import { useElementInteractions } from '../hooks/use-element-interactions';
10
+
10
11
  type InteractionsContextValue = {
12
+ elementId: string;
11
13
  interactions: ElementInteractions;
12
14
  setInteractions: ( value: ElementInteractions | undefined ) => void;
13
15
  playInteractions: ( interactionId: string ) => void;
@@ -44,6 +46,7 @@ export const InteractionsProvider = ( { children, elementId }: { children: React
44
46
  };
45
47
 
46
48
  const contextValue: InteractionsContextValue = {
49
+ elementId,
47
50
  interactions,
48
51
  setInteractions,
49
52
  playInteractions,
@@ -0,0 +1,26 @@
1
+ import { useState } from 'react';
2
+ import { type ElementID, type ElementInteractions, getElementInteractions } from '@elementor/editor-elements';
3
+ import { __privateUseListenTo as useListenTo, windowEvent } from '@elementor/editor-v1-adapters';
4
+
5
+ import { filterInteractions } from '../utils/filter-interactions';
6
+
7
+ export const useElementInteractions = ( elementId: ElementID ) => {
8
+ const [ interactions, setInteractions ] = useState< ElementInteractions >( () => {
9
+ const initial = getElementInteractions( elementId );
10
+ const filteredInteractions = filterInteractions( initial?.items ?? [] );
11
+
12
+ return { version: initial?.version ?? 1, items: filteredInteractions };
13
+ } );
14
+
15
+ useListenTo(
16
+ windowEvent( 'elementor/element/update_interactions' ),
17
+ () => {
18
+ const newInteractions = getElementInteractions( elementId );
19
+ const filteredInteractions = filterInteractions( newInteractions?.items ?? [] );
20
+ setInteractions( { version: newInteractions?.version ?? 1, items: filteredInteractions } );
21
+ },
22
+ [ elementId ]
23
+ );
24
+
25
+ return interactions;
26
+ };
package/src/index.ts CHANGED
@@ -16,3 +16,28 @@ export { TRIGGER_OPTIONS, BASE_TRIGGERS } from './components/controls/trigger';
16
16
  export { EASING_OPTIONS, BASE_EASINGS } from './components/controls/easing';
17
17
  export { REPLAY_OPTIONS, BASE_REPLAY } from './components/controls/replay';
18
18
  export { EFFECT_OPTIONS, BASE_EFFECTS } from './components/controls/effect';
19
+
20
+ export {
21
+ createString,
22
+ createNumber,
23
+ createBoolean,
24
+ createTimingConfig,
25
+ createConfig,
26
+ createExcludedBreakpoints,
27
+ createInteractionBreakpoints,
28
+ createAnimationPreset,
29
+ createInteractionItem,
30
+ createDefaultInteractionItem,
31
+ createDefaultInteractions,
32
+ extractString,
33
+ extractBoolean,
34
+ extractSize,
35
+ extractExcludedBreakpoints,
36
+ buildDisplayLabel,
37
+ } from './utils/prop-value-utils';
38
+
39
+ export { generateTempInteractionId, isTempId } from './utils/temp-id-utils';
40
+ export { resolveDirection } from './utils/resolve-direction';
41
+ export { convertTimeUnit } from './utils/time-conversion';
42
+ export { parseSizeValue, formatSizeValue } from './utils/size-transform-utils';
43
+ export { useElementInteractions } from './hooks/use-element-interactions';
package/src/init.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { initPasteInteractionsCommand } from './commands/paste-interactions';
1
2
  import { Direction } from './components/controls/direction';
2
3
  import { Easing } from './components/controls/easing';
3
4
  import { Effect } from './components/controls/effect';
@@ -15,6 +16,7 @@ export function init() {
15
16
  interactionsRepository.register( documentElementsInteractionsProvider );
16
17
 
17
18
  initCleanInteractionIdsOnDuplicate();
19
+ initPasteInteractionsCommand();
18
20
 
19
21
  registerInteractionsControl( {
20
22
  type: 'trigger',
@@ -31,7 +33,7 @@ export function init() {
31
33
  registerInteractionsControl( {
32
34
  type: 'replay',
33
35
  component: Replay,
34
- options: [ 'true', 'false' ],
36
+ options: [ 'no' ],
35
37
  } );
36
38
 
37
39
  registerInteractionsControl( {
@@ -1,9 +1,15 @@
1
1
  import { type ComponentType } from 'react';
2
2
  import { type PropValue } from '@elementor/editor-props';
3
3
 
4
- import { type DirectionFieldProps, type FieldProps, type ReplayFieldProps } from './types';
4
+ import {
5
+ type DirectionFieldProps,
6
+ type FieldProps,
7
+ type RepeatFieldProps,
8
+ type ReplayFieldProps,
9
+ type TimesFieldProps,
10
+ } from './types';
5
11
 
6
- type InteractionsControlType =
12
+ export type InteractionsControlType =
7
13
  | 'trigger'
8
14
  | 'effect'
9
15
  | 'effectType'
@@ -11,6 +17,8 @@ type InteractionsControlType =
11
17
  | 'duration'
12
18
  | 'delay'
13
19
  | 'replay'
20
+ | 'repeat'
21
+ | 'times'
14
22
  | 'easing'
15
23
  | 'relativeTo'
16
24
  | 'start'
@@ -26,6 +34,8 @@ type InteractionsControlPropsMap = {
26
34
  duration: FieldProps;
27
35
  delay: FieldProps;
28
36
  replay: ReplayFieldProps;
37
+ repeat: RepeatFieldProps;
38
+ times: TimesFieldProps;
29
39
  easing: FieldProps;
30
40
  relativeTo: FieldProps;
31
41
  start: FieldProps;
@@ -40,7 +50,9 @@ type ControlOptions< T extends InteractionsControlType > = {
40
50
 
41
51
  type StoredControlOptions = {
42
52
  type: InteractionsControlType;
43
- component: ComponentType< FieldProps | DirectionFieldProps | ReplayFieldProps >;
53
+ component: ComponentType<
54
+ FieldProps | DirectionFieldProps | ReplayFieldProps | RepeatFieldProps | TimesFieldProps
55
+ >;
44
56
  options?: string[];
45
57
  };
46
58