@elementor/editor-components 3.33.0-260 → 3.33.0-262
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.js +117 -19
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +107 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +16 -15
- package/src/components/create-component-form/create-component-form.tsx +32 -5
- package/src/components/create-component-form/utils/get-component-event-data.ts +54 -0
- package/src/components/create-component-form/utils/replace-element-with-component.ts +2 -2
- package/src/create-component-type.ts +30 -3
- package/src/init.ts +6 -0
- package/src/utils/tracking.ts +47 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { useEffect, useMemo, useState } from 'react';
|
|
3
|
-
import { getElementLabel, type
|
|
2
|
+
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
3
|
+
import { getElementLabel, type V1ElementData } from '@elementor/editor-elements';
|
|
4
4
|
import { ThemeProvider } from '@elementor/editor-ui';
|
|
5
5
|
import { StarIcon } from '@elementor/icons';
|
|
6
6
|
import { __useDispatch as useDispatch } from '@elementor/store';
|
|
@@ -11,13 +11,20 @@ import { __ } from '@wordpress/i18n';
|
|
|
11
11
|
import { useComponents } from '../../hooks/use-components';
|
|
12
12
|
import { slice } from '../../store/store';
|
|
13
13
|
import { type ComponentFormValues } from '../../types';
|
|
14
|
+
import { trackComponentEvent } from '../../utils/tracking';
|
|
14
15
|
import { useForm } from './hooks/use-form';
|
|
15
16
|
import { createBaseComponentSchema, createSubmitComponentSchema } from './utils/component-form-schema';
|
|
17
|
+
import {
|
|
18
|
+
type ComponentEventData,
|
|
19
|
+
type ContextMenuEventOptions,
|
|
20
|
+
getComponentEventData,
|
|
21
|
+
} from './utils/get-component-event-data';
|
|
16
22
|
import { replaceElementWithComponent } from './utils/replace-element-with-component';
|
|
17
23
|
|
|
18
24
|
type SaveAsComponentEventData = {
|
|
19
|
-
element:
|
|
25
|
+
element: V1ElementData;
|
|
20
26
|
anchorPosition: { top: number; left: number };
|
|
27
|
+
options?: ContextMenuEventOptions;
|
|
21
28
|
};
|
|
22
29
|
|
|
23
30
|
type ResultNotification = {
|
|
@@ -28,7 +35,7 @@ type ResultNotification = {
|
|
|
28
35
|
|
|
29
36
|
export function CreateComponentForm() {
|
|
30
37
|
const [ element, setElement ] = useState< {
|
|
31
|
-
element:
|
|
38
|
+
element: V1ElementData;
|
|
32
39
|
elementLabel: string;
|
|
33
40
|
} | null >( null );
|
|
34
41
|
|
|
@@ -38,12 +45,20 @@ export function CreateComponentForm() {
|
|
|
38
45
|
|
|
39
46
|
const dispatch = useDispatch();
|
|
40
47
|
|
|
48
|
+
const eventData = useRef< ComponentEventData | null >( null );
|
|
49
|
+
|
|
41
50
|
useEffect( () => {
|
|
42
51
|
const OPEN_SAVE_AS_COMPONENT_FORM_EVENT = 'elementor/editor/open-save-as-component-form';
|
|
43
52
|
|
|
44
53
|
const openPopup = ( event: CustomEvent< SaveAsComponentEventData > ) => {
|
|
45
54
|
setElement( { element: event.detail.element, elementLabel: getElementLabel( event.detail.element.id ) } );
|
|
46
55
|
setAnchorPosition( event.detail.anchorPosition );
|
|
56
|
+
|
|
57
|
+
eventData.current = getComponentEventData( event.detail.element, event.detail.options );
|
|
58
|
+
trackComponentEvent( {
|
|
59
|
+
action: 'createClicked',
|
|
60
|
+
...eventData.current,
|
|
61
|
+
} );
|
|
47
62
|
};
|
|
48
63
|
|
|
49
64
|
window.addEventListener( OPEN_SAVE_AS_COMPONENT_FORM_EVENT, openPopup as EventListener );
|
|
@@ -65,7 +80,7 @@ export function CreateComponentForm() {
|
|
|
65
80
|
slice.actions.addUnpublished( {
|
|
66
81
|
uid,
|
|
67
82
|
name: values.componentName,
|
|
68
|
-
elements: [ element.element
|
|
83
|
+
elements: [ element.element ],
|
|
69
84
|
} )
|
|
70
85
|
);
|
|
71
86
|
|
|
@@ -73,6 +88,13 @@ export function CreateComponentForm() {
|
|
|
73
88
|
|
|
74
89
|
replaceElementWithComponent( element.element, { uid, name: values.componentName } );
|
|
75
90
|
|
|
91
|
+
trackComponentEvent( {
|
|
92
|
+
action: 'created',
|
|
93
|
+
component_uid: uid,
|
|
94
|
+
component_name: values.componentName,
|
|
95
|
+
...eventData.current,
|
|
96
|
+
} );
|
|
97
|
+
|
|
76
98
|
setResultNotification( {
|
|
77
99
|
show: true,
|
|
78
100
|
// Translators: %1$s: Component name, %2$s: Component UID
|
|
@@ -100,6 +122,11 @@ export function CreateComponentForm() {
|
|
|
100
122
|
|
|
101
123
|
const cancelSave = () => {
|
|
102
124
|
resetAndClosePopup();
|
|
125
|
+
|
|
126
|
+
trackComponentEvent( {
|
|
127
|
+
action: 'createCancelled',
|
|
128
|
+
...eventData.current,
|
|
129
|
+
} );
|
|
103
130
|
};
|
|
104
131
|
|
|
105
132
|
return (
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type V1ElementData } from '@elementor/editor-elements';
|
|
2
|
+
|
|
3
|
+
export type ComponentEventData = {
|
|
4
|
+
nested_elements_count: number;
|
|
5
|
+
nested_components_count: number;
|
|
6
|
+
top_element_type: string;
|
|
7
|
+
location?: string;
|
|
8
|
+
secondary_location?: string;
|
|
9
|
+
trigger?: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type ContextMenuEventOptions = Record< string, unknown > & {
|
|
13
|
+
location: string;
|
|
14
|
+
secondaryLocation: string;
|
|
15
|
+
trigger: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const getComponentEventData = (
|
|
19
|
+
containerElement: V1ElementData,
|
|
20
|
+
options?: ContextMenuEventOptions
|
|
21
|
+
): ComponentEventData => {
|
|
22
|
+
const { elementsCount, componentsCount } = countNestedElements( containerElement );
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
nested_elements_count: elementsCount,
|
|
26
|
+
nested_components_count: componentsCount,
|
|
27
|
+
top_element_type: containerElement.elType,
|
|
28
|
+
location: options?.location,
|
|
29
|
+
secondary_location: options?.secondaryLocation,
|
|
30
|
+
trigger: options?.trigger,
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
function countNestedElements( container: V1ElementData ): { elementsCount: number; componentsCount: number } {
|
|
35
|
+
if ( ! container.elements || container.elements.length === 0 ) {
|
|
36
|
+
return { elementsCount: 0, componentsCount: 0 };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let elementsCount = container.elements.length;
|
|
40
|
+
let componentsCount = 0;
|
|
41
|
+
|
|
42
|
+
for ( const element of container.elements ) {
|
|
43
|
+
if ( element.widgetType === 'e-component' ) {
|
|
44
|
+
componentsCount++;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const { elementsCount: nestedElementsCount, componentsCount: nestedComponentsCount } =
|
|
48
|
+
countNestedElements( element );
|
|
49
|
+
elementsCount += nestedElementsCount;
|
|
50
|
+
componentsCount += nestedComponentsCount;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return { elementsCount, componentsCount };
|
|
54
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { replaceElement, type
|
|
1
|
+
import { replaceElement, type V1ElementData, type V1ElementModelProps } from '@elementor/editor-elements';
|
|
2
2
|
|
|
3
3
|
type ComponentInstanceParams = {
|
|
4
4
|
id?: number;
|
|
@@ -6,7 +6,7 @@ type ComponentInstanceParams = {
|
|
|
6
6
|
uid: string;
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
-
export const replaceElementWithComponent = ( element:
|
|
9
|
+
export const replaceElementWithComponent = ( element: V1ElementData, component: ComponentInstanceParams ) => {
|
|
10
10
|
replaceElement( {
|
|
11
11
|
currentElement: element,
|
|
12
12
|
newElement: createComponentModel( component ),
|
|
@@ -12,6 +12,10 @@ import { __privateRunCommand as runCommand } from '@elementor/editor-v1-adapters
|
|
|
12
12
|
import { __ } from '@wordpress/i18n';
|
|
13
13
|
|
|
14
14
|
import { apiClient } from './api';
|
|
15
|
+
import { type ExtendedWindow } from './types';
|
|
16
|
+
import { trackComponentEvent } from './utils/tracking';
|
|
17
|
+
|
|
18
|
+
type ContextMenuEventData = { location: string; secondaryLocation: string; trigger: string };
|
|
15
19
|
|
|
16
20
|
export const TYPE = 'e-component';
|
|
17
21
|
|
|
@@ -35,7 +39,8 @@ function createComponentView(
|
|
|
35
39
|
options: CreateTemplatedElementTypeOptions & { showLockedByModal?: ( lockedBy: string ) => void }
|
|
36
40
|
): typeof ElementView {
|
|
37
41
|
return class extends createTemplatedElementView( options ) {
|
|
38
|
-
legacyWindow = window as unknown as LegacyWindow;
|
|
42
|
+
legacyWindow = window as unknown as LegacyWindow & ExtendedWindow;
|
|
43
|
+
eventsManagerConfig = this.legacyWindow.elementorCommon.eventsManager.config;
|
|
39
44
|
|
|
40
45
|
afterSettingsResolve( settings: { [ key: string ]: unknown } ) {
|
|
41
46
|
if ( settings.component ) {
|
|
@@ -86,7 +91,8 @@ function createComponentView(
|
|
|
86
91
|
icon: 'eicon-edit',
|
|
87
92
|
title: () => __( 'Edit Component', 'elementor' ),
|
|
88
93
|
isEnabled: () => true,
|
|
89
|
-
callback: () =>
|
|
94
|
+
callback: ( _: unknown, eventData: ContextMenuEventData ) =>
|
|
95
|
+
this.editComponent( eventData ),
|
|
90
96
|
},
|
|
91
97
|
],
|
|
92
98
|
},
|
|
@@ -111,10 +117,31 @@ function createComponentView(
|
|
|
111
117
|
}
|
|
112
118
|
}
|
|
113
119
|
|
|
120
|
+
editComponent( { trigger, location, secondaryLocation }: ContextMenuEventData ) {
|
|
121
|
+
this.switchDocument();
|
|
122
|
+
|
|
123
|
+
const editorSettings = this.model.get( 'editor_settings' );
|
|
124
|
+
|
|
125
|
+
trackComponentEvent( {
|
|
126
|
+
action: 'edited',
|
|
127
|
+
component_uid: editorSettings?.component_uid,
|
|
128
|
+
component_name: editorSettings?.title,
|
|
129
|
+
location,
|
|
130
|
+
secondary_location: secondaryLocation,
|
|
131
|
+
trigger,
|
|
132
|
+
} );
|
|
133
|
+
}
|
|
134
|
+
|
|
114
135
|
handleDblClick( e: MouseEvent ) {
|
|
115
136
|
e.stopPropagation();
|
|
116
137
|
|
|
117
|
-
this.
|
|
138
|
+
const { triggers, locations, secondaryLocations } = this.eventsManagerConfig;
|
|
139
|
+
|
|
140
|
+
this.editComponent( {
|
|
141
|
+
trigger: triggers.doubleClick,
|
|
142
|
+
location: locations.canvas,
|
|
143
|
+
secondaryLocation: secondaryLocations.canvasElement,
|
|
144
|
+
} );
|
|
118
145
|
}
|
|
119
146
|
|
|
120
147
|
events() {
|
package/src/init.ts
CHANGED
|
@@ -25,15 +25,19 @@ import { removeComponentStyles } from './store/remove-component-styles';
|
|
|
25
25
|
import { slice } from './store/store';
|
|
26
26
|
import { beforeSave } from './sync/before-save';
|
|
27
27
|
import { type ExtendedWindow } from './types';
|
|
28
|
+
import { onElementDrop } from './utils/tracking';
|
|
28
29
|
|
|
29
30
|
const COMPONENT_DOCUMENT_TYPE = 'elementor_component';
|
|
30
31
|
|
|
31
32
|
export function init() {
|
|
32
33
|
stylesRepository.register( componentsStylesProvider );
|
|
34
|
+
|
|
33
35
|
registerSlice( slice );
|
|
36
|
+
|
|
34
37
|
registerElementType( TYPE, ( options: CreateTemplatedElementTypeOptions ) =>
|
|
35
38
|
createComponentType( { ...options, showLockedByModal: openEditModeDialog } )
|
|
36
39
|
);
|
|
40
|
+
|
|
37
41
|
registerDataHook( 'dependency', 'editor/documents/close', ( args ) => {
|
|
38
42
|
const document = getV1CurrentDocument();
|
|
39
43
|
if ( document.config.type === COMPONENT_DOCUMENT_TYPE ) {
|
|
@@ -42,6 +46,8 @@ export function init() {
|
|
|
42
46
|
return true;
|
|
43
47
|
} );
|
|
44
48
|
|
|
49
|
+
registerDataHook( 'after', 'preview/drop', onElementDrop );
|
|
50
|
+
|
|
45
51
|
( window as unknown as ExtendedWindow ).elementorCommon.__beforeSave = beforeSave;
|
|
46
52
|
|
|
47
53
|
injectTab( {
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type V1Element } from '@elementor/editor-elements';
|
|
2
|
+
import { getMixpanel } from '@elementor/mixpanel';
|
|
3
|
+
import { __getState as getState } from '@elementor/store';
|
|
4
|
+
|
|
5
|
+
import { selectCreatedThisSession } from '../store/store';
|
|
6
|
+
import { type ExtendedWindow } from '../types';
|
|
7
|
+
|
|
8
|
+
type ComponentEventData = Record< string, unknown > & {
|
|
9
|
+
action: 'createClicked' | 'created' | 'createCancelled' | 'instanceAdded' | 'edited';
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const trackComponentEvent = ( { action, ...data }: ComponentEventData ) => {
|
|
13
|
+
const { dispatchEvent, config } = getMixpanel();
|
|
14
|
+
if ( ! config?.names?.components?.[ action ] ) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const name = config.names.components[ action ];
|
|
19
|
+
dispatchEvent?.( name, data );
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const onElementDrop = ( _args: unknown, element: V1Element ) => {
|
|
23
|
+
if ( ! ( element.model.get( 'widgetType' ) === 'e-component' ) ) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const editorSettings = element.model.get( 'editor_settings' );
|
|
28
|
+
const componentName = editorSettings?.title;
|
|
29
|
+
const componentUID = editorSettings?.component_uid;
|
|
30
|
+
const instanceId = element.id;
|
|
31
|
+
|
|
32
|
+
const createdThisSession = selectCreatedThisSession( getState() );
|
|
33
|
+
const isSameSessionReuse = componentUID && createdThisSession.includes( componentUID );
|
|
34
|
+
|
|
35
|
+
const eventsManagerConfig = ( window as unknown as ExtendedWindow ).elementorCommon.eventsManager.config;
|
|
36
|
+
const { locations, secondaryLocations } = eventsManagerConfig;
|
|
37
|
+
|
|
38
|
+
trackComponentEvent( {
|
|
39
|
+
action: 'instanceAdded',
|
|
40
|
+
instance_id: instanceId,
|
|
41
|
+
component_uid: componentUID,
|
|
42
|
+
component_name: componentName,
|
|
43
|
+
is_same_session_reuse: isSameSessionReuse,
|
|
44
|
+
location: locations.widgetPanel,
|
|
45
|
+
secondary_location: secondaryLocations.componentsTab,
|
|
46
|
+
} );
|
|
47
|
+
};
|