@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.
- package/dist/index.d.mts +123 -5
- package/dist/index.d.ts +123 -5
- package/dist/index.js +861 -334
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +823 -312
- package/dist/index.mjs.map +1 -1
- package/package.json +12 -11
- package/src/commands/get-clipboard-elements.ts +11 -0
- package/src/commands/paste-interactions.ts +136 -0
- package/src/components/controls/easing.tsx +3 -0
- package/src/components/controls/effect.tsx +3 -0
- package/src/components/controls/repeat.tsx +57 -0
- package/src/components/controls/replay.tsx +15 -13
- package/src/components/controls/trigger.tsx +3 -0
- package/src/components/interaction-details.tsx +162 -120
- package/src/components/interactions-list.tsx +16 -3
- package/src/components/interactions-tab.tsx +4 -1
- package/src/contexts/interactions-context.tsx +4 -1
- package/src/hooks/use-element-interactions.ts +26 -0
- package/src/index.ts +26 -0
- package/src/init.ts +13 -3
- package/src/interactions-controls-registry.ts +15 -3
- package/src/mcp/constants.ts +58 -0
- package/src/mcp/index.ts +15 -69
- package/src/mcp/tools/manage-element-interaction-tool.ts +40 -5
- package/src/mcp/tools/schema.ts +1 -1
- package/src/types.ts +6 -1
- package/src/ui/interactions-promotion-chip.tsx +14 -6
- package/src/ui/promotion-overlay-layout.tsx +22 -0
- package/src/ui/promotion-select.tsx +4 -0
- package/src/utils/custom-effect-to-prop-value.ts +145 -0
- package/src/utils/filter-interactions.ts +9 -0
- package/src/utils/get-interactions-config.ts +1 -11
- package/src/utils/is-supported-interaction-item.ts +39 -0
- package/src/utils/prop-value-utils.ts +59 -34
- package/src/utils/tracking.ts +42 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { type ComponentType, useMemo
|
|
2
|
+
import { type ComponentType, useMemo } from 'react';
|
|
3
3
|
import { PopoverContent } from '@elementor/editor-controls';
|
|
4
4
|
import { type PropValue } from '@elementor/editor-props';
|
|
5
|
-
import {
|
|
5
|
+
import { Divider, Grid } from '@elementor/ui';
|
|
6
6
|
import { __ } from '@wordpress/i18n';
|
|
7
7
|
|
|
8
8
|
import { getInteractionsControl } from '../interactions-controls-registry';
|
|
@@ -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,10 +172,16 @@ 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
|
-
const containerRef = useRef< HTMLDivElement >( null );
|
|
157
|
-
|
|
158
185
|
const updateInteraction = (
|
|
159
186
|
updates: Partial< {
|
|
160
187
|
trigger: string;
|
|
@@ -166,6 +193,8 @@ export const InteractionDetails = ( { interaction, onChange, onPlayInteraction }
|
|
|
166
193
|
replay: boolean;
|
|
167
194
|
easing?: string;
|
|
168
195
|
relativeTo: string;
|
|
196
|
+
repeat: string;
|
|
197
|
+
times?: number;
|
|
169
198
|
start: SizeStringValue;
|
|
170
199
|
end: SizeStringValue;
|
|
171
200
|
customEffects?: PropValue;
|
|
@@ -192,6 +221,8 @@ export const InteractionDetails = ( { interaction, onChange, onPlayInteraction }
|
|
|
192
221
|
replay: updates.replay ?? replay,
|
|
193
222
|
easing: updates.easing ?? easing,
|
|
194
223
|
relativeTo: updates.relativeTo ?? relativeTo,
|
|
224
|
+
repeat: updates.repeat ?? repeat,
|
|
225
|
+
times: updates.times ?? times,
|
|
195
226
|
start: updates.start ?? start,
|
|
196
227
|
end: updates.end ?? end,
|
|
197
228
|
customEffects: updates.customEffects ?? customEffects,
|
|
@@ -208,131 +239,142 @@ export const InteractionDetails = ( { interaction, onChange, onPlayInteraction }
|
|
|
208
239
|
};
|
|
209
240
|
|
|
210
241
|
return (
|
|
211
|
-
<
|
|
212
|
-
<
|
|
213
|
-
|
|
214
|
-
{
|
|
215
|
-
<
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
onChange={ ( v ) => updateInteraction( { trigger: v } ) }
|
|
219
|
-
/>
|
|
220
|
-
</Field>
|
|
221
|
-
) }
|
|
222
|
-
|
|
223
|
-
{ ReplayControl && (
|
|
224
|
-
<Field label={ __( 'Replay', 'elementor' ) }>
|
|
225
|
-
<ReplayControl
|
|
226
|
-
value={ replay }
|
|
227
|
-
onChange={ ( v ) => updateInteraction( { replay: v } ) }
|
|
228
|
-
disabled={ true }
|
|
229
|
-
anchorRef={ containerRef }
|
|
230
|
-
/>
|
|
231
|
-
</Field>
|
|
232
|
-
) }
|
|
233
|
-
</Grid>
|
|
242
|
+
<PopoverContent p={ 1.5 }>
|
|
243
|
+
<Grid container spacing={ 1.5 }>
|
|
244
|
+
{ TriggerControl && (
|
|
245
|
+
<Field label={ __( 'Trigger', 'elementor' ) }>
|
|
246
|
+
<TriggerControl value={ trigger } onChange={ ( v ) => updateInteraction( { trigger: v } ) } />
|
|
247
|
+
</Field>
|
|
248
|
+
) }
|
|
234
249
|
|
|
235
|
-
|
|
250
|
+
{ ReplayControl && (
|
|
251
|
+
<Field label={ __( 'Replay', 'elementor' ) }>
|
|
252
|
+
<ReplayControl
|
|
253
|
+
value={ replay }
|
|
254
|
+
onChange={ ( v ) => updateInteraction( { replay: v } ) }
|
|
255
|
+
disabled={ true }
|
|
256
|
+
/>
|
|
257
|
+
</Field>
|
|
258
|
+
) }
|
|
259
|
+
</Grid>
|
|
236
260
|
|
|
237
|
-
|
|
238
|
-
{ EffectControl && (
|
|
239
|
-
<Field label={ __( 'Effect', 'elementor' ) }>
|
|
240
|
-
<EffectControl value={ effect } onChange={ ( v ) => updateInteraction( { effect: v } ) } />
|
|
241
|
-
</Field>
|
|
242
|
-
) }
|
|
261
|
+
<Divider />
|
|
243
262
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
</Field>
|
|
251
|
-
) }
|
|
263
|
+
<Grid container spacing={ 1.5 }>
|
|
264
|
+
{ EffectControl && (
|
|
265
|
+
<Field label={ __( 'Effect', 'elementor' ) }>
|
|
266
|
+
<EffectControl value={ effect } onChange={ ( v ) => updateInteraction( { effect: v } ) } />
|
|
267
|
+
</Field>
|
|
268
|
+
) }
|
|
252
269
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
<DirectionControl
|
|
262
|
-
value={ direction }
|
|
263
|
-
onChange={ ( v ) => updateInteraction( { direction: v } ) }
|
|
264
|
-
interactionType={ type }
|
|
265
|
-
/>
|
|
266
|
-
</Field>
|
|
267
|
-
) }
|
|
268
|
-
|
|
269
|
-
{ controlVisibilityConfig.duration( interactionValues ) && (
|
|
270
|
-
<Field label={ __( 'Duration', 'elementor' ) }>
|
|
271
|
-
<TimeFrameIndicator
|
|
272
|
-
value={ String( duration ) }
|
|
273
|
-
onChange={ ( v ) => updateInteraction( { duration: v as SizeStringValue } ) }
|
|
274
|
-
defaultValue={ DEFAULT_VALUES.duration as SizeStringValue }
|
|
275
|
-
/>
|
|
276
|
-
</Field>
|
|
277
|
-
) }
|
|
278
|
-
|
|
279
|
-
{ controlVisibilityConfig.delay( interactionValues ) && (
|
|
280
|
-
<Field label={ __( 'Delay', 'elementor' ) }>
|
|
281
|
-
<TimeFrameIndicator
|
|
282
|
-
value={ String( delay ) }
|
|
283
|
-
onChange={ ( v ) => updateInteraction( { delay: v as SizeStringValue } ) }
|
|
284
|
-
defaultValue={ DEFAULT_VALUES.delay as SizeStringValue }
|
|
285
|
-
/>
|
|
286
|
-
</Field>
|
|
287
|
-
) }
|
|
288
|
-
</Grid>
|
|
270
|
+
{ CustomEffectControl && (
|
|
271
|
+
<Field label={ __( 'Custom Effect', 'elementor' ) }>
|
|
272
|
+
<CustomEffectControl
|
|
273
|
+
value={ customEffects }
|
|
274
|
+
onChange={ ( v: PropValue ) => updateInteraction( { customEffects: v } ) }
|
|
275
|
+
/>
|
|
276
|
+
</Field>
|
|
277
|
+
) }
|
|
289
278
|
|
|
290
|
-
{
|
|
291
|
-
|
|
292
|
-
<
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
279
|
+
{ EffectTypeControl && (
|
|
280
|
+
<Field label={ __( 'Type', 'elementor' ) }>
|
|
281
|
+
<EffectTypeControl value={ type } onChange={ ( v ) => updateInteraction( { type: v } ) } />
|
|
282
|
+
</Field>
|
|
283
|
+
) }
|
|
284
|
+
|
|
285
|
+
{ DirectionControl && (
|
|
286
|
+
<Field label={ __( 'Direction', 'elementor' ) }>
|
|
287
|
+
<DirectionControl
|
|
288
|
+
value={ direction }
|
|
289
|
+
onChange={ ( v ) => updateInteraction( { direction: v } ) }
|
|
290
|
+
interactionType={ type }
|
|
291
|
+
/>
|
|
292
|
+
</Field>
|
|
293
|
+
) }
|
|
294
|
+
|
|
295
|
+
{ RepeatControl && (
|
|
296
|
+
<Field label={ __( 'Repeat', 'elementor' ) }>
|
|
297
|
+
<RepeatControl value={ repeat } onChange={ ( v ) => updateInteraction( { repeat: v } ) } />
|
|
298
|
+
</Field>
|
|
299
|
+
) }
|
|
300
|
+
|
|
301
|
+
{ TimesControl && (
|
|
302
|
+
<Field label={ __( 'Times', 'elementor' ) }>
|
|
303
|
+
<TimesControl
|
|
304
|
+
value={ times }
|
|
305
|
+
onChange={ ( v ) =>
|
|
306
|
+
updateInteraction( {
|
|
307
|
+
times: normalizeTimesValue( v, DEFAULT_VALUES.times ),
|
|
308
|
+
} )
|
|
309
|
+
}
|
|
310
|
+
/>
|
|
311
|
+
</Field>
|
|
312
|
+
) }
|
|
313
|
+
|
|
314
|
+
{ controlVisibilityConfig.duration( interactionValues ) && (
|
|
315
|
+
<Field label={ __( 'Duration', 'elementor' ) }>
|
|
316
|
+
<TimeFrameIndicator
|
|
317
|
+
value={ String( duration ) }
|
|
318
|
+
onChange={ ( v ) => updateInteraction( { duration: v as SizeStringValue } ) }
|
|
319
|
+
defaultValue={ DEFAULT_VALUES.duration as SizeStringValue }
|
|
320
|
+
/>
|
|
321
|
+
</Field>
|
|
322
|
+
) }
|
|
323
|
+
|
|
324
|
+
{ controlVisibilityConfig.delay( interactionValues ) && (
|
|
325
|
+
<Field label={ __( 'Delay', 'elementor' ) }>
|
|
326
|
+
<TimeFrameIndicator
|
|
327
|
+
value={ String( delay ) }
|
|
328
|
+
onChange={ ( v ) => updateInteraction( { delay: v as SizeStringValue } ) }
|
|
329
|
+
defaultValue={ DEFAULT_VALUES.delay as SizeStringValue }
|
|
330
|
+
/>
|
|
331
|
+
</Field>
|
|
321
332
|
) }
|
|
333
|
+
</Grid>
|
|
322
334
|
|
|
323
|
-
|
|
335
|
+
{ controlVisibilityConfig.relativeTo( interactionValues ) && RelativeToControl && (
|
|
336
|
+
<>
|
|
337
|
+
<Divider />
|
|
324
338
|
<Grid container spacing={ 1.5 }>
|
|
325
|
-
|
|
326
|
-
<
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
updateInteraction( {
|
|
330
|
-
|
|
339
|
+
{ StartControl && (
|
|
340
|
+
<Field label={ __( 'Start', 'elementor' ) }>
|
|
341
|
+
<StartControl
|
|
342
|
+
value={ parseSizeValue( start, [ '%' ] ).size?.toString() ?? '' }
|
|
343
|
+
onChange={ ( v: string ) => updateInteraction( { start: v as SizeStringValue } ) }
|
|
344
|
+
/>
|
|
345
|
+
</Field>
|
|
346
|
+
) }
|
|
347
|
+
{ EndControl && (
|
|
348
|
+
<Field label={ __( 'End', 'elementor' ) }>
|
|
349
|
+
<EndControl
|
|
350
|
+
value={ parseSizeValue( end, [ '%' ] ).size?.toString() ?? '' }
|
|
351
|
+
onChange={ ( v: string ) => updateInteraction( { end: v as SizeStringValue } ) }
|
|
352
|
+
/>
|
|
353
|
+
</Field>
|
|
354
|
+
) }
|
|
355
|
+
<Field label={ __( 'Relative To', 'elementor' ) }>
|
|
356
|
+
<RelativeToControl
|
|
357
|
+
value={ relativeTo }
|
|
358
|
+
onChange={ ( v ) => updateInteraction( { relativeTo: v } ) }
|
|
331
359
|
/>
|
|
332
360
|
</Field>
|
|
333
361
|
</Grid>
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
362
|
+
<Divider />
|
|
363
|
+
</>
|
|
364
|
+
) }
|
|
365
|
+
|
|
366
|
+
{ EasingControl && (
|
|
367
|
+
<Grid container spacing={ 1.5 }>
|
|
368
|
+
<Field label={ __( 'Easing', 'elementor' ) }>
|
|
369
|
+
<EasingControl
|
|
370
|
+
value={ easing }
|
|
371
|
+
onChange={ ( v ) => {
|
|
372
|
+
updateInteraction( { easing: v } );
|
|
373
|
+
} }
|
|
374
|
+
/>
|
|
375
|
+
</Field>
|
|
376
|
+
</Grid>
|
|
377
|
+
) }
|
|
378
|
+
</PopoverContent>
|
|
337
379
|
);
|
|
338
380
|
};
|
|
@@ -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
|
-
(
|
|
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,29 @@ 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
|
+
export { REPEAT_OPTIONS, REPEAT_TOOLTIPS } from './components/controls/repeat';
|
|
20
|
+
|
|
21
|
+
export {
|
|
22
|
+
createString,
|
|
23
|
+
createNumber,
|
|
24
|
+
createBoolean,
|
|
25
|
+
createTimingConfig,
|
|
26
|
+
createConfig,
|
|
27
|
+
createExcludedBreakpoints,
|
|
28
|
+
createInteractionBreakpoints,
|
|
29
|
+
createAnimationPreset,
|
|
30
|
+
createInteractionItem,
|
|
31
|
+
createDefaultInteractionItem,
|
|
32
|
+
createDefaultInteractions,
|
|
33
|
+
extractString,
|
|
34
|
+
extractBoolean,
|
|
35
|
+
extractSize,
|
|
36
|
+
extractExcludedBreakpoints,
|
|
37
|
+
buildDisplayLabel,
|
|
38
|
+
} from './utils/prop-value-utils';
|
|
39
|
+
|
|
40
|
+
export { generateTempInteractionId, isTempId } from './utils/temp-id-utils';
|
|
41
|
+
export { resolveDirection } from './utils/resolve-direction';
|
|
42
|
+
export { convertTimeUnit } from './utils/time-conversion';
|
|
43
|
+
export { parseSizeValue, formatSizeValue } from './utils/size-transform-utils';
|
|
44
|
+
export { useElementInteractions } from './hooks/use-element-interactions';
|
package/src/init.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
+
import { getMCPByDomain } from '@elementor/editor-mcp';
|
|
2
|
+
|
|
3
|
+
import { initPasteInteractionsCommand } from './commands/paste-interactions';
|
|
1
4
|
import { Direction } from './components/controls/direction';
|
|
2
5
|
import { Easing } from './components/controls/easing';
|
|
3
6
|
import { Effect } from './components/controls/effect';
|
|
4
7
|
import { EffectType } from './components/controls/effect-type';
|
|
8
|
+
import { Repeat } from './components/controls/repeat';
|
|
5
9
|
import { Replay } from './components/controls/replay';
|
|
6
10
|
import { Trigger } from './components/controls/trigger';
|
|
7
11
|
import { initCleanInteractionIdsOnDuplicate } from './hooks/on-duplicate';
|
|
8
12
|
import { registerInteractionsControl } from './interactions-controls-registry';
|
|
9
13
|
import { interactionsRepository } from './interactions-repository';
|
|
10
|
-
import { initMcpInteractions } from './mcp';
|
|
14
|
+
import { EDITOR_INTERACTIONS_MCP_INSTRUCTIONS, initMcpInteractions } from './mcp';
|
|
11
15
|
import { documentElementsInteractionsProvider } from './providers/document-elements-interactions-provider';
|
|
12
16
|
|
|
13
17
|
export function init() {
|
|
@@ -15,6 +19,7 @@ export function init() {
|
|
|
15
19
|
interactionsRepository.register( documentElementsInteractionsProvider );
|
|
16
20
|
|
|
17
21
|
initCleanInteractionIdsOnDuplicate();
|
|
22
|
+
initPasteInteractionsCommand();
|
|
18
23
|
|
|
19
24
|
registerInteractionsControl( {
|
|
20
25
|
type: 'trigger',
|
|
@@ -31,7 +36,7 @@ export function init() {
|
|
|
31
36
|
registerInteractionsControl( {
|
|
32
37
|
type: 'replay',
|
|
33
38
|
component: Replay,
|
|
34
|
-
options: [ '
|
|
39
|
+
options: [ 'no' ],
|
|
35
40
|
} );
|
|
36
41
|
|
|
37
42
|
registerInteractionsControl( {
|
|
@@ -52,7 +57,12 @@ export function init() {
|
|
|
52
57
|
options: [ 'fade', 'slide', 'scale' ],
|
|
53
58
|
} );
|
|
54
59
|
|
|
55
|
-
|
|
60
|
+
registerInteractionsControl( {
|
|
61
|
+
type: 'repeat',
|
|
62
|
+
component: Repeat,
|
|
63
|
+
} );
|
|
64
|
+
|
|
65
|
+
initMcpInteractions( getMCPByDomain( 'interactions', { instructions: EDITOR_INTERACTIONS_MCP_INSTRUCTIONS } ) );
|
|
56
66
|
} catch ( error ) {
|
|
57
67
|
throw error;
|
|
58
68
|
}
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { type ComponentType } from 'react';
|
|
2
2
|
import { type PropValue } from '@elementor/editor-props';
|
|
3
3
|
|
|
4
|
-
import {
|
|
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<
|
|
53
|
+
component: ComponentType<
|
|
54
|
+
FieldProps | DirectionFieldProps | ReplayFieldProps | RepeatFieldProps | TimesFieldProps
|
|
55
|
+
>;
|
|
44
56
|
options?: string[];
|
|
45
57
|
};
|
|
46
58
|
|