@elementor/editor-components 3.33.0-252 → 3.33.0-254
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 +78 -70
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +62 -54
- package/dist/index.mjs.map +1 -1
- package/package.json +15 -15
- package/src/api.ts +4 -4
- package/src/component-id-transformer.ts +15 -9
- package/src/components/components-tab/components-item.tsx +6 -2
- package/src/components/components-tab/components-list.tsx +1 -1
- package/src/components/consts.ts +1 -0
- package/src/components/create-component-form/create-component-form.tsx +18 -18
- package/src/components/create-component-form/utils/replace-element-with-component.ts +10 -7
- package/src/components/edit-component/edit-component.tsx +3 -5
- package/src/store/store.ts +24 -22
- package/src/sync/create-components-before-save.ts +17 -16
- package/src/types.ts +20 -2
|
@@ -25,7 +25,7 @@ export function ComponentsList() {
|
|
|
25
25
|
return (
|
|
26
26
|
<List sx={ { display: 'flex', flexDirection: 'column', gap: 1, px: 2 } }>
|
|
27
27
|
{ components.map( ( component ) => (
|
|
28
|
-
<ComponentItem key={ component.
|
|
28
|
+
<ComponentItem key={ component.uid } component={ component } />
|
|
29
29
|
) ) }
|
|
30
30
|
</List>
|
|
31
31
|
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const COMPONENT_DOCUMENT_TYPE = 'elementor_component';
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { useEffect, useMemo, useState } from 'react';
|
|
3
|
-
import { getElementLabel, type V1Element } from '@elementor/editor-elements';
|
|
3
|
+
import { getElementLabel, type V1Element, 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';
|
|
7
7
|
import { Alert, Button, FormLabel, Grid, Popover, Snackbar, Stack, TextField, Typography } from '@elementor/ui';
|
|
8
|
+
import { generateUniqueId } from '@elementor/utils';
|
|
8
9
|
import { __ } from '@wordpress/i18n';
|
|
9
10
|
|
|
10
11
|
import { useComponents } from '../../hooks/use-components';
|
|
@@ -52,33 +53,32 @@ export function CreateComponentForm() {
|
|
|
52
53
|
};
|
|
53
54
|
}, [] );
|
|
54
55
|
|
|
55
|
-
const handleSave =
|
|
56
|
+
const handleSave = ( values: ComponentFormValues ) => {
|
|
56
57
|
try {
|
|
57
58
|
if ( ! element ) {
|
|
58
59
|
throw new Error( `Can't save element as component: element not found` );
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
const
|
|
62
|
+
const uid = generateUniqueId( 'component' );
|
|
62
63
|
|
|
63
64
|
dispatch(
|
|
64
65
|
slice.actions.addUnpublished( {
|
|
65
|
-
|
|
66
|
+
uid,
|
|
66
67
|
name: values.componentName,
|
|
67
|
-
elements: [ element.element.model.toJSON( { remove: [ 'default' ] } ) ],
|
|
68
|
+
elements: [ element.element.model.toJSON( { remove: [ 'default' ] } ) as V1ElementData ],
|
|
68
69
|
} )
|
|
69
70
|
);
|
|
70
71
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
} );
|
|
72
|
+
dispatch( slice.actions.addCreatedThisSession( uid ) );
|
|
73
|
+
|
|
74
|
+
replaceElementWithComponent( element.element, { uid, name: values.componentName } );
|
|
75
75
|
|
|
76
76
|
setResultNotification( {
|
|
77
77
|
show: true,
|
|
78
|
-
// Translators: %1$s: Component name, %2$s: Component
|
|
79
|
-
message: __( 'Component saved successfully as: %1$s (
|
|
78
|
+
// Translators: %1$s: Component name, %2$s: Component UID
|
|
79
|
+
message: __( 'Component saved successfully as: %1$s (UID: %2$s)', 'elementor' )
|
|
80
80
|
.replace( '%1$s', values.componentName )
|
|
81
|
-
.replace( '%2$s',
|
|
81
|
+
.replace( '%2$s', uid ),
|
|
82
82
|
type: 'success',
|
|
83
83
|
} );
|
|
84
84
|
|
|
@@ -98,11 +98,15 @@ export function CreateComponentForm() {
|
|
|
98
98
|
setAnchorPosition( undefined );
|
|
99
99
|
};
|
|
100
100
|
|
|
101
|
+
const cancelSave = () => {
|
|
102
|
+
resetAndClosePopup();
|
|
103
|
+
};
|
|
104
|
+
|
|
101
105
|
return (
|
|
102
106
|
<ThemeProvider>
|
|
103
107
|
<Popover
|
|
104
108
|
open={ element !== null }
|
|
105
|
-
onClose={
|
|
109
|
+
onClose={ cancelSave }
|
|
106
110
|
anchorReference="anchorPosition"
|
|
107
111
|
anchorPosition={ anchorPosition }
|
|
108
112
|
>
|
|
@@ -110,7 +114,7 @@ export function CreateComponentForm() {
|
|
|
110
114
|
<Form
|
|
111
115
|
initialValues={ { componentName: element.elementLabel } }
|
|
112
116
|
handleSave={ handleSave }
|
|
113
|
-
closePopup={
|
|
117
|
+
closePopup={ cancelSave }
|
|
114
118
|
/>
|
|
115
119
|
) }
|
|
116
120
|
</Popover>
|
|
@@ -215,7 +219,3 @@ const Form = ( {
|
|
|
215
219
|
</Stack>
|
|
216
220
|
);
|
|
217
221
|
};
|
|
218
|
-
|
|
219
|
-
export const generateTempId = () => {
|
|
220
|
-
return Date.now() + Math.floor( Math.random() * 1000000 );
|
|
221
|
-
};
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import { replaceElement, type V1Element } from '@elementor/editor-elements';
|
|
1
|
+
import { replaceElement, type V1Element, type V1ElementModelProps } from '@elementor/editor-elements';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
type ComponentInstanceParams = {
|
|
4
|
+
id?: number;
|
|
5
|
+
name: string;
|
|
6
|
+
uid: string;
|
|
7
|
+
};
|
|
4
8
|
|
|
5
|
-
export const replaceElementWithComponent = ( element: V1Element, component:
|
|
9
|
+
export const replaceElementWithComponent = ( element: V1Element, component: ComponentInstanceParams ) => {
|
|
6
10
|
replaceElement( {
|
|
7
11
|
currentElement: element,
|
|
8
12
|
newElement: createComponentModel( component ),
|
|
@@ -10,20 +14,19 @@ export const replaceElementWithComponent = ( element: V1Element, component: Comp
|
|
|
10
14
|
} );
|
|
11
15
|
};
|
|
12
16
|
|
|
13
|
-
export const createComponentModel = (
|
|
14
|
-
component: Component
|
|
15
|
-
): Parameters< typeof replaceElement >[ 0 ][ 'newElement' ] => {
|
|
17
|
+
export const createComponentModel = ( component: ComponentInstanceParams ): Omit< V1ElementModelProps, 'id' > => {
|
|
16
18
|
return {
|
|
17
19
|
elType: 'widget',
|
|
18
20
|
widgetType: 'e-component',
|
|
19
21
|
settings: {
|
|
20
22
|
component: {
|
|
21
23
|
$$type: 'component-id',
|
|
22
|
-
value: component.id,
|
|
24
|
+
value: component.id ?? component.uid,
|
|
23
25
|
},
|
|
24
26
|
},
|
|
25
27
|
editor_settings: {
|
|
26
28
|
title: component.name,
|
|
29
|
+
component_uid: component.uid,
|
|
27
30
|
},
|
|
28
31
|
};
|
|
29
32
|
};
|
|
@@ -7,10 +7,9 @@ import {
|
|
|
7
7
|
__privateRunCommand as runCommand,
|
|
8
8
|
commandEndEvent,
|
|
9
9
|
} from '@elementor/editor-v1-adapters';
|
|
10
|
-
import { __useSelector as useSelector } from '@elementor/store';
|
|
11
10
|
|
|
12
11
|
import { apiClient } from '../../api';
|
|
13
|
-
import {
|
|
12
|
+
import { COMPONENT_DOCUMENT_TYPE } from '../consts';
|
|
14
13
|
import { ComponentModal } from './component-modal';
|
|
15
14
|
|
|
16
15
|
type ComponentsPathItem = {
|
|
@@ -41,7 +40,6 @@ function useHandleDocumentSwitches(
|
|
|
41
40
|
path: ComponentsPathItem[],
|
|
42
41
|
setPath: Dispatch< SetStateAction< ComponentsPathItem[] > >
|
|
43
42
|
) {
|
|
44
|
-
const components = useSelector( selectComponentsObject );
|
|
45
43
|
const documentsManager = getV1DocumentsManager();
|
|
46
44
|
|
|
47
45
|
useEffect(
|
|
@@ -59,7 +57,7 @@ function useHandleDocumentSwitches(
|
|
|
59
57
|
apiClient.unlockComponent( currentComponentId );
|
|
60
58
|
}
|
|
61
59
|
|
|
62
|
-
const isComponent =
|
|
60
|
+
const isComponent = nextDocument.config.type === COMPONENT_DOCUMENT_TYPE;
|
|
63
61
|
|
|
64
62
|
if ( ! isComponent ) {
|
|
65
63
|
setPath( [] );
|
|
@@ -69,7 +67,7 @@ function useHandleDocumentSwitches(
|
|
|
69
67
|
|
|
70
68
|
setPath( getUpdatedComponentPath( path, nextDocument ) );
|
|
71
69
|
} ),
|
|
72
|
-
[ path, setPath,
|
|
70
|
+
[ path, setPath, documentsManager ]
|
|
73
71
|
);
|
|
74
72
|
}
|
|
75
73
|
|
package/src/store/store.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { type V1ElementData } from '@elementor/editor-elements';
|
|
2
1
|
import {
|
|
3
2
|
__createSelector as createSelector,
|
|
4
3
|
__createSlice as createSlice,
|
|
@@ -6,22 +5,25 @@ import {
|
|
|
6
5
|
type SliceState,
|
|
7
6
|
} from '@elementor/store';
|
|
8
7
|
|
|
9
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
type Component,
|
|
10
|
+
type ComponentId,
|
|
11
|
+
type PublishedComponent,
|
|
12
|
+
type StylesDefinition,
|
|
13
|
+
type UnpublishedComponent,
|
|
14
|
+
} from '../types';
|
|
10
15
|
import { loadComponents } from './thunks';
|
|
11
16
|
|
|
12
|
-
type GetComponentResponse =
|
|
13
|
-
|
|
14
|
-
export type UnpublishedComponent = Component & {
|
|
15
|
-
elements: V1ElementData[];
|
|
16
|
-
};
|
|
17
|
+
type GetComponentResponse = PublishedComponent[];
|
|
17
18
|
|
|
18
19
|
type Status = 'idle' | 'pending' | 'error';
|
|
19
20
|
|
|
20
21
|
type ComponentsState = {
|
|
21
|
-
data:
|
|
22
|
+
data: PublishedComponent[];
|
|
22
23
|
unpublishedData: UnpublishedComponent[];
|
|
23
24
|
loadStatus: Status;
|
|
24
25
|
styles: StylesDefinition;
|
|
26
|
+
createdThisSession: Component[ 'uid' ][];
|
|
25
27
|
};
|
|
26
28
|
|
|
27
29
|
type ComponentsSlice = SliceState< typeof slice >;
|
|
@@ -31,6 +33,7 @@ export const initialState: ComponentsState = {
|
|
|
31
33
|
unpublishedData: [],
|
|
32
34
|
loadStatus: 'idle',
|
|
33
35
|
styles: {},
|
|
36
|
+
createdThisSession: [],
|
|
34
37
|
};
|
|
35
38
|
|
|
36
39
|
export const SLICE_NAME = 'components';
|
|
@@ -38,17 +41,17 @@ export const slice = createSlice( {
|
|
|
38
41
|
name: SLICE_NAME,
|
|
39
42
|
initialState,
|
|
40
43
|
reducers: {
|
|
41
|
-
add: ( state, { payload }: PayloadAction<
|
|
44
|
+
add: ( state, { payload }: PayloadAction< PublishedComponent | PublishedComponent[] > ) => {
|
|
42
45
|
if ( Array.isArray( payload ) ) {
|
|
43
46
|
state.data = [ ...state.data, ...payload ];
|
|
44
47
|
} else {
|
|
45
48
|
state.data.unshift( payload );
|
|
46
49
|
}
|
|
47
50
|
},
|
|
48
|
-
load: ( state, { payload }: PayloadAction<
|
|
51
|
+
load: ( state, { payload }: PayloadAction< PublishedComponent[] > ) => {
|
|
49
52
|
state.data = payload;
|
|
50
53
|
},
|
|
51
|
-
addUnpublished: ( state, { payload } ) => {
|
|
54
|
+
addUnpublished: ( state, { payload }: PayloadAction< UnpublishedComponent > ) => {
|
|
52
55
|
state.unpublishedData.unshift( payload );
|
|
53
56
|
},
|
|
54
57
|
resetUnpublished: ( state ) => {
|
|
@@ -62,6 +65,9 @@ export const slice = createSlice( {
|
|
|
62
65
|
addStyles: ( state, { payload } ) => {
|
|
63
66
|
state.styles = { ...state.styles, ...payload };
|
|
64
67
|
},
|
|
68
|
+
addCreatedThisSession: ( state, { payload }: PayloadAction< string > ) => {
|
|
69
|
+
state.createdThisSession.push( payload );
|
|
70
|
+
},
|
|
65
71
|
},
|
|
66
72
|
extraReducers: ( builder ) => {
|
|
67
73
|
builder.addCase( loadComponents.fulfilled, ( state, { payload }: PayloadAction< GetComponentResponse > ) => {
|
|
@@ -81,12 +87,13 @@ const selectData = ( state: ComponentsSlice ) => state[ SLICE_NAME ].data;
|
|
|
81
87
|
const selectLoadStatus = ( state: ComponentsSlice ) => state[ SLICE_NAME ].loadStatus;
|
|
82
88
|
const selectStylesDefinitions = ( state: ComponentsSlice ) => state[ SLICE_NAME ].styles ?? {};
|
|
83
89
|
const selectUnpublishedData = ( state: ComponentsSlice ) => state[ SLICE_NAME ].unpublishedData;
|
|
90
|
+
const getCreatedThisSession = ( state: ComponentsSlice ) => state[ SLICE_NAME ].createdThisSession;
|
|
84
91
|
|
|
85
92
|
export const selectComponents = createSelector(
|
|
86
93
|
selectData,
|
|
87
94
|
selectUnpublishedData,
|
|
88
|
-
( data:
|
|
89
|
-
...unpublishedData.map( ( item ) => ( {
|
|
95
|
+
( data: PublishedComponent[], unpublishedData: UnpublishedComponent[] ) => [
|
|
96
|
+
...unpublishedData.map( ( item ) => ( { uid: item.uid, name: item.name } ) ),
|
|
90
97
|
...data,
|
|
91
98
|
]
|
|
92
99
|
);
|
|
@@ -94,16 +101,11 @@ export const selectUnpublishedComponents = createSelector(
|
|
|
94
101
|
selectUnpublishedData,
|
|
95
102
|
( unpublishedData: UnpublishedComponent[] ) => unpublishedData
|
|
96
103
|
);
|
|
97
|
-
export const selectComponentsObject = createSelector(
|
|
98
|
-
selectData,
|
|
99
|
-
selectUnpublishedData,
|
|
100
|
-
( data: Component[], unpublishedData: UnpublishedComponent[] ) =>
|
|
101
|
-
data.concat( unpublishedData ).reduce< Record< ComponentId, Component > >( ( acc, component ) => {
|
|
102
|
-
acc[ component.id ] = component;
|
|
103
|
-
return acc;
|
|
104
|
-
}, {} )
|
|
105
|
-
);
|
|
106
104
|
export const selectLoadIsPending = createSelector( selectLoadStatus, ( status ) => status === 'pending' );
|
|
107
105
|
export const selectLoadIsError = createSelector( selectLoadStatus, ( status ) => status === 'error' );
|
|
108
106
|
export const selectStyles = ( state: ComponentsSlice ) => state[ SLICE_NAME ].styles ?? {};
|
|
109
107
|
export const selectFlatStyles = createSelector( selectStylesDefinitions, ( data ) => Object.values( data ).flat() );
|
|
108
|
+
export const selectCreatedThisSession = createSelector(
|
|
109
|
+
getCreatedThisSession,
|
|
110
|
+
( createdThisSession ) => createdThisSession
|
|
111
|
+
);
|
|
@@ -3,8 +3,8 @@ import { type TransformablePropValue } from '@elementor/editor-props';
|
|
|
3
3
|
import { __dispatch as dispatch, __getState as getState } from '@elementor/store';
|
|
4
4
|
|
|
5
5
|
import { apiClient } from '../api';
|
|
6
|
-
import { selectUnpublishedComponents, slice
|
|
7
|
-
import { type Container, type DocumentSaveStatus } from '../types';
|
|
6
|
+
import { selectUnpublishedComponents, slice } from '../store/store';
|
|
7
|
+
import { type Container, type DocumentSaveStatus, type UnpublishedComponent } from '../types';
|
|
8
8
|
|
|
9
9
|
export async function createComponentsBeforeSave( {
|
|
10
10
|
container,
|
|
@@ -20,16 +20,17 @@ export async function createComponentsBeforeSave( {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
try {
|
|
23
|
-
const
|
|
23
|
+
const uidToComponentId = await createComponents( unpublishedComponents, status );
|
|
24
24
|
|
|
25
25
|
const elements = container.model.get( 'elements' ).toJSON();
|
|
26
|
-
updateComponentInstances( elements,
|
|
26
|
+
updateComponentInstances( elements, uidToComponentId );
|
|
27
27
|
|
|
28
28
|
dispatch(
|
|
29
29
|
slice.actions.add(
|
|
30
30
|
unpublishedComponents.map( ( component ) => ( {
|
|
31
|
-
id:
|
|
31
|
+
id: uidToComponentId.get( component.uid ) as number,
|
|
32
32
|
name: component.name,
|
|
33
|
+
uid: component.uid,
|
|
33
34
|
} ) )
|
|
34
35
|
)
|
|
35
36
|
);
|
|
@@ -42,47 +43,47 @@ export async function createComponentsBeforeSave( {
|
|
|
42
43
|
async function createComponents(
|
|
43
44
|
components: UnpublishedComponent[],
|
|
44
45
|
status: DocumentSaveStatus
|
|
45
|
-
): Promise< Map<
|
|
46
|
+
): Promise< Map< string, number > > {
|
|
46
47
|
const response = await apiClient.create( {
|
|
47
48
|
status,
|
|
48
49
|
items: components.map( ( component ) => ( {
|
|
49
|
-
|
|
50
|
+
uid: component.uid,
|
|
50
51
|
title: component.name,
|
|
51
52
|
elements: component.elements,
|
|
52
53
|
} ) ),
|
|
53
54
|
} );
|
|
54
55
|
|
|
55
|
-
const map = new Map<
|
|
56
|
+
const map = new Map< string, number >();
|
|
56
57
|
|
|
57
58
|
Object.entries( response ).forEach( ( [ key, value ] ) => {
|
|
58
|
-
map.set(
|
|
59
|
+
map.set( key, value );
|
|
59
60
|
} );
|
|
60
61
|
|
|
61
62
|
return map;
|
|
62
63
|
}
|
|
63
64
|
|
|
64
|
-
function updateComponentInstances( elements: V1ElementData[],
|
|
65
|
+
function updateComponentInstances( elements: V1ElementData[], uidToComponentId: Map< string, number > ): void {
|
|
65
66
|
elements.forEach( ( element ) => {
|
|
66
|
-
const { shouldUpdate, newComponentId } = shouldUpdateElement( element,
|
|
67
|
+
const { shouldUpdate, newComponentId } = shouldUpdateElement( element, uidToComponentId );
|
|
67
68
|
if ( shouldUpdate ) {
|
|
68
69
|
updateElementComponentId( element.id, newComponentId );
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
if ( element.elements ) {
|
|
72
|
-
updateComponentInstances( element.elements,
|
|
73
|
+
updateComponentInstances( element.elements, uidToComponentId );
|
|
73
74
|
}
|
|
74
75
|
} );
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
function shouldUpdateElement(
|
|
78
79
|
element: V1ElementData,
|
|
79
|
-
|
|
80
|
+
uidToComponentId: Map< string, number >
|
|
80
81
|
): { shouldUpdate: true; newComponentId: number } | { shouldUpdate: false; newComponentId: null } {
|
|
81
82
|
if ( element.widgetType === 'e-component' ) {
|
|
82
|
-
const currentComponentId = ( element.settings?.component as TransformablePropValue< 'component-id',
|
|
83
|
+
const currentComponentId = ( element.settings?.component as TransformablePropValue< 'component-id', string > )
|
|
83
84
|
?.value;
|
|
84
|
-
if ( currentComponentId &&
|
|
85
|
-
return { shouldUpdate: true, newComponentId:
|
|
85
|
+
if ( currentComponentId && uidToComponentId.has( currentComponentId ) ) {
|
|
86
|
+
return { shouldUpdate: true, newComponentId: uidToComponentId.get( currentComponentId ) as number };
|
|
86
87
|
}
|
|
87
88
|
}
|
|
88
89
|
return { shouldUpdate: false, newComponentId: null };
|
package/src/types.ts
CHANGED
|
@@ -9,8 +9,18 @@ export type ComponentId = number;
|
|
|
9
9
|
|
|
10
10
|
export type StylesDefinition = Record< ComponentId, StyleDefinition[] >;
|
|
11
11
|
|
|
12
|
-
export type Component =
|
|
12
|
+
export type Component = PublishedComponent | UnpublishedComponent;
|
|
13
|
+
|
|
14
|
+
export type PublishedComponent = BaseComponent & {
|
|
13
15
|
id: number;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type UnpublishedComponent = BaseComponent & {
|
|
19
|
+
elements: V1ElementData[];
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
type BaseComponent = {
|
|
23
|
+
uid: string;
|
|
14
24
|
name: string;
|
|
15
25
|
};
|
|
16
26
|
|
|
@@ -18,7 +28,15 @@ export type DocumentStatus = 'publish' | 'draft';
|
|
|
18
28
|
export type DocumentSaveStatus = DocumentStatus | 'autosave';
|
|
19
29
|
|
|
20
30
|
export type ExtendedWindow = Window & {
|
|
21
|
-
elementorCommon: Record< string, unknown
|
|
31
|
+
elementorCommon: Record< string, unknown > & {
|
|
32
|
+
eventsManager: {
|
|
33
|
+
config: {
|
|
34
|
+
locations: Record< string, string >;
|
|
35
|
+
secondaryLocations: Record< string, string >;
|
|
36
|
+
triggers: Record< string, string >;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
};
|
|
22
40
|
};
|
|
23
41
|
|
|
24
42
|
export type Container = {
|