@elementor/editor-components 3.35.0-420 → 3.35.0-422
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 +397 -298
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +322 -212
- package/dist/index.mjs.map +1 -1
- package/package.json +22 -22
- package/src/components/components-tab/angie-promotion-modal.tsx +72 -0
- package/src/components/components-tab/components-list.tsx +91 -32
- package/src/components/components-tab/components.tsx +14 -2
- package/src/store/actions/rename-component.ts +42 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-components",
|
|
3
3
|
"description": "Elementor editor components",
|
|
4
|
-
"version": "3.35.0-
|
|
4
|
+
"version": "3.35.0-422",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "Elementor Team",
|
|
7
7
|
"homepage": "https://elementor.com/",
|
|
@@ -40,30 +40,30 @@
|
|
|
40
40
|
"dev": "tsup --config=../../tsup.dev.ts"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@elementor/editor": "3.35.0-
|
|
44
|
-
"@elementor/editor-canvas": "3.35.0-
|
|
45
|
-
"@elementor/editor-controls": "3.35.0-
|
|
46
|
-
"@elementor/editor-documents": "3.35.0-
|
|
47
|
-
"@elementor/editor-editing-panel": "3.35.0-
|
|
48
|
-
"@elementor/editor-elements": "3.35.0-
|
|
49
|
-
"@elementor/editor-elements-panel": "3.35.0-
|
|
50
|
-
"@elementor/editor-mcp": "3.35.0-
|
|
51
|
-
"@elementor/editor-panels": "3.35.0-
|
|
52
|
-
"@elementor/editor-props": "3.35.0-
|
|
53
|
-
"@elementor/editor-styles-repository": "3.35.0-
|
|
54
|
-
"@elementor/editor-ui": "3.35.0-
|
|
55
|
-
"@elementor/editor-v1-adapters": "3.35.0-
|
|
56
|
-
"@elementor/http-client": "3.35.0-
|
|
43
|
+
"@elementor/editor": "3.35.0-422",
|
|
44
|
+
"@elementor/editor-canvas": "3.35.0-422",
|
|
45
|
+
"@elementor/editor-controls": "3.35.0-422",
|
|
46
|
+
"@elementor/editor-documents": "3.35.0-422",
|
|
47
|
+
"@elementor/editor-editing-panel": "3.35.0-422",
|
|
48
|
+
"@elementor/editor-elements": "3.35.0-422",
|
|
49
|
+
"@elementor/editor-elements-panel": "3.35.0-422",
|
|
50
|
+
"@elementor/editor-mcp": "3.35.0-422",
|
|
51
|
+
"@elementor/editor-panels": "3.35.0-422",
|
|
52
|
+
"@elementor/editor-props": "3.35.0-422",
|
|
53
|
+
"@elementor/editor-styles-repository": "3.35.0-422",
|
|
54
|
+
"@elementor/editor-ui": "3.35.0-422",
|
|
55
|
+
"@elementor/editor-v1-adapters": "3.35.0-422",
|
|
56
|
+
"@elementor/http-client": "3.35.0-422",
|
|
57
57
|
"@elementor/icons": "^1.63.0",
|
|
58
|
-
"@elementor/mixpanel": "3.35.0-
|
|
59
|
-
"@elementor/query": "3.35.0-
|
|
60
|
-
"@elementor/schema": "3.35.0-
|
|
61
|
-
"@elementor/store": "3.35.0-
|
|
58
|
+
"@elementor/mixpanel": "3.35.0-422",
|
|
59
|
+
"@elementor/query": "3.35.0-422",
|
|
60
|
+
"@elementor/schema": "3.35.0-422",
|
|
61
|
+
"@elementor/store": "3.35.0-422",
|
|
62
62
|
"@elementor/ui": "1.36.17",
|
|
63
|
-
"@elementor/utils": "3.35.0-
|
|
63
|
+
"@elementor/utils": "3.35.0-422",
|
|
64
64
|
"@wordpress/i18n": "^5.13.0",
|
|
65
|
-
"@elementor/editor-notifications": "3.35.0-
|
|
66
|
-
"@elementor/editor-current-user": "3.35.0-
|
|
65
|
+
"@elementor/editor-notifications": "3.35.0-422",
|
|
66
|
+
"@elementor/editor-current-user": "3.35.0-422"
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|
|
69
69
|
"react": "^18.3.1",
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
Button,
|
|
4
|
+
Card,
|
|
5
|
+
CardActions,
|
|
6
|
+
CardContent,
|
|
7
|
+
CardHeader,
|
|
8
|
+
CardMedia,
|
|
9
|
+
ClickAwayListener,
|
|
10
|
+
CloseButton,
|
|
11
|
+
Infotip,
|
|
12
|
+
Typography,
|
|
13
|
+
} from '@elementor/ui';
|
|
14
|
+
import { __ } from '@wordpress/i18n';
|
|
15
|
+
|
|
16
|
+
const ANGIE_INSTALL_URL = '/wp-admin/plugin-install.php?tab=plugin-information&plugin=angie';
|
|
17
|
+
const PLACEHOLDER_IMAGE_URL = 'https://assets.elementor.com/packages/v1/images/components-angie-promo.svg';
|
|
18
|
+
|
|
19
|
+
type AngiePromotionCardProps = {
|
|
20
|
+
onClose: () => void;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
type AngiePromotionModalProps = React.PropsWithChildren< {
|
|
24
|
+
open: boolean;
|
|
25
|
+
onClose: () => void;
|
|
26
|
+
} >;
|
|
27
|
+
|
|
28
|
+
export const AngiePromotionModal = ( { children, open, onClose }: AngiePromotionModalProps ) => {
|
|
29
|
+
return (
|
|
30
|
+
<Infotip placement="right-end" arrow content={ <AngiePromotionCard onClose={ onClose } /> } open={ open }>
|
|
31
|
+
{ children }
|
|
32
|
+
</Infotip>
|
|
33
|
+
);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
function AngiePromotionCard( { onClose }: AngiePromotionCardProps ) {
|
|
37
|
+
const handleCtaClick = () => {
|
|
38
|
+
window.open( ANGIE_INSTALL_URL, '_blank' );
|
|
39
|
+
onClose();
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<ClickAwayListener disableReactTree mouseEvent="onMouseDown" touchEvent="onTouchStart" onClickAway={ onClose }>
|
|
44
|
+
<Card elevation={ 0 } sx={ { maxWidth: 296 } }>
|
|
45
|
+
<CardHeader
|
|
46
|
+
title={ __( 'Add new component with AI', 'elementor' ) }
|
|
47
|
+
titleTypographyProps={ { variant: 'subtitle2' } }
|
|
48
|
+
action={ <CloseButton slotProps={ { icon: { fontSize: 'tiny' } } } onClick={ onClose } /> }
|
|
49
|
+
/>
|
|
50
|
+
<CardMedia
|
|
51
|
+
component="img"
|
|
52
|
+
image={ PLACEHOLDER_IMAGE_URL }
|
|
53
|
+
alt=""
|
|
54
|
+
sx={ { width: '100%', aspectRatio: '16 / 9' } }
|
|
55
|
+
/>
|
|
56
|
+
<CardContent>
|
|
57
|
+
<Typography variant="body2" color="text.secondary">
|
|
58
|
+
{ __(
|
|
59
|
+
'Angie our AI assistant can easily create new components and save you the hassle of doing it yourself',
|
|
60
|
+
'elementor'
|
|
61
|
+
) }
|
|
62
|
+
</Typography>
|
|
63
|
+
</CardContent>
|
|
64
|
+
<CardActions sx={ { justifyContent: 'flex-end' } }>
|
|
65
|
+
<Button size="medium" variant="contained" color="accent" onClick={ handleCtaClick }>
|
|
66
|
+
{ __( 'Get Angie', 'elementor' ) }
|
|
67
|
+
</Button>
|
|
68
|
+
</CardActions>
|
|
69
|
+
</Card>
|
|
70
|
+
</ClickAwayListener>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
@@ -1,14 +1,26 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { getAngieSdk } from '@elementor/editor-mcp';
|
|
4
|
+
import { AIIcon, ComponentsIcon } from '@elementor/icons';
|
|
5
|
+
import { Box, Button, Divider, Link, List, Stack, Typography } from '@elementor/ui';
|
|
4
6
|
import { __ } from '@wordpress/i18n';
|
|
5
7
|
|
|
6
8
|
import { useComponents } from '../../hooks/use-components';
|
|
7
9
|
import { renameComponent } from '../../store/actions/rename-component';
|
|
10
|
+
import { AngiePromotionModal } from './angie-promotion-modal';
|
|
8
11
|
import { ComponentItem } from './components-item';
|
|
9
12
|
import { LoadingComponents } from './loading-components';
|
|
10
13
|
import { useSearch } from './search-provider';
|
|
11
14
|
|
|
15
|
+
const LEARN_MORE_URL = 'http://go.elementor.com/components-guide-article';
|
|
16
|
+
|
|
17
|
+
// Override legacy panel CSS reset that sets h1-h6 to font-size:100% and font-weight:normal.
|
|
18
|
+
// See: assets/dev/scss/editor/panel/_reset.scss (applied via :where() selector in panel.scss).
|
|
19
|
+
const SUBTITLE_OVERRIDE_SX = {
|
|
20
|
+
fontSize: '0.875rem !important',
|
|
21
|
+
fontWeight: '500 !important',
|
|
22
|
+
};
|
|
23
|
+
|
|
12
24
|
export function ComponentsList() {
|
|
13
25
|
const { components, isLoading, searchValue } = useFilteredComponents();
|
|
14
26
|
|
|
@@ -39,41 +51,87 @@ export function ComponentsList() {
|
|
|
39
51
|
}
|
|
40
52
|
|
|
41
53
|
const EmptyState = () => {
|
|
54
|
+
const [ isAngieModalOpen, setIsAngieModalOpen ] = useState( false );
|
|
55
|
+
|
|
56
|
+
const handleCreateWithAI = () => {
|
|
57
|
+
const sdk = getAngieSdk();
|
|
58
|
+
|
|
59
|
+
if ( sdk.isAngieReady() ) {
|
|
60
|
+
sdk.triggerAngie( {
|
|
61
|
+
prompt: __(
|
|
62
|
+
'Create a [hero/testimonial/product card/CTA/feature] component for my [business type]. Include [describe what you want]',
|
|
63
|
+
'elementor'
|
|
64
|
+
),
|
|
65
|
+
context: { source: 'components-panel-empty-state' },
|
|
66
|
+
} );
|
|
67
|
+
} else {
|
|
68
|
+
setIsAngieModalOpen( true );
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
42
72
|
return (
|
|
43
73
|
<Stack
|
|
44
74
|
alignItems="center"
|
|
45
|
-
justifyContent="
|
|
75
|
+
justifyContent="start"
|
|
46
76
|
height="100%"
|
|
47
|
-
sx={ { px: 2
|
|
48
|
-
gap={
|
|
77
|
+
sx={ { px: 2, py: 4 } }
|
|
78
|
+
gap={ 2 }
|
|
49
79
|
overflow="hidden"
|
|
50
80
|
>
|
|
51
|
-
<
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
{
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
81
|
+
<Stack alignItems="center" gap={ 1 }>
|
|
82
|
+
<ComponentsIcon fontSize="large" sx={ { color: 'text.secondary' } } />
|
|
83
|
+
|
|
84
|
+
<Typography align="center" variant="subtitle2" color="text.secondary" sx={ SUBTITLE_OVERRIDE_SX }>
|
|
85
|
+
{ __( 'No components yet', 'elementor' ) }
|
|
86
|
+
</Typography>
|
|
87
|
+
|
|
88
|
+
<Typography align="center" variant="caption" color="secondary" sx={ { maxWidth: 200 } }>
|
|
89
|
+
{ __( 'Components are reusable blocks that sync across your site.', 'elementor' ) }
|
|
90
|
+
<br />
|
|
91
|
+
{ __( 'Create once, use everywhere.', 'elementor' ) }
|
|
92
|
+
</Typography>
|
|
93
|
+
|
|
94
|
+
<Link
|
|
95
|
+
href={ LEARN_MORE_URL }
|
|
96
|
+
target="_blank"
|
|
97
|
+
rel="noopener noreferrer"
|
|
98
|
+
variant="caption"
|
|
99
|
+
color="info.main"
|
|
100
|
+
>
|
|
101
|
+
{ __( 'Learn more about components', 'elementor' ) }
|
|
102
|
+
</Link>
|
|
103
|
+
</Stack>
|
|
104
|
+
|
|
105
|
+
<Divider sx={ { width: '100%' } } />
|
|
106
|
+
|
|
107
|
+
<Stack alignItems="center" gap={ 1 } width="100%">
|
|
108
|
+
<Typography align="center" variant="subtitle2" color="text.secondary" sx={ SUBTITLE_OVERRIDE_SX }>
|
|
109
|
+
{ __( 'Create your first one:', 'elementor' ) }
|
|
110
|
+
</Typography>
|
|
111
|
+
|
|
112
|
+
<Typography align="center" variant="caption" color="secondary" sx={ { maxWidth: 228 } }>
|
|
113
|
+
{ __(
|
|
114
|
+
'Right-click any div-block or flexbox on your canvas or structure and select "Create component"',
|
|
115
|
+
'elementor'
|
|
116
|
+
) }
|
|
117
|
+
</Typography>
|
|
118
|
+
|
|
119
|
+
<Typography align="center" variant="caption" color="secondary">
|
|
120
|
+
{ __( 'Or', 'elementor' ) }
|
|
121
|
+
</Typography>
|
|
122
|
+
|
|
123
|
+
<AngiePromotionModal open={ isAngieModalOpen } onClose={ () => setIsAngieModalOpen( false ) }>
|
|
124
|
+
<Button
|
|
125
|
+
color="secondary"
|
|
126
|
+
variant="outlined"
|
|
127
|
+
size="small"
|
|
128
|
+
onClick={ handleCreateWithAI }
|
|
129
|
+
endIcon={ <AIIcon /> }
|
|
130
|
+
>
|
|
131
|
+
{ __( 'Create component with AI', 'elementor' ) }
|
|
132
|
+
</Button>
|
|
133
|
+
</AngiePromotionModal>
|
|
134
|
+
</Stack>
|
|
77
135
|
</Stack>
|
|
78
136
|
);
|
|
79
137
|
};
|
|
@@ -95,7 +153,7 @@ const EmptySearchResult = () => {
|
|
|
95
153
|
width: '100%',
|
|
96
154
|
} }
|
|
97
155
|
>
|
|
98
|
-
<Typography align="center" variant="subtitle2" color="inherit">
|
|
156
|
+
<Typography align="center" variant="subtitle2" color="inherit" sx={ SUBTITLE_OVERRIDE_SX }>
|
|
99
157
|
{ __( 'Sorry, nothing matched', 'elementor' ) }
|
|
100
158
|
</Typography>
|
|
101
159
|
{ searchValue && (
|
|
@@ -103,6 +161,7 @@ const EmptySearchResult = () => {
|
|
|
103
161
|
variant="subtitle2"
|
|
104
162
|
color="inherit"
|
|
105
163
|
sx={ {
|
|
164
|
+
...SUBTITLE_OVERRIDE_SX,
|
|
106
165
|
display: 'flex',
|
|
107
166
|
width: '100%',
|
|
108
167
|
justifyContent: 'center',
|
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { ThemeProvider } from '@elementor/editor-ui';
|
|
3
3
|
|
|
4
|
+
import { useComponents } from '../../hooks/use-components';
|
|
4
5
|
import { ComponentSearch } from './component-search';
|
|
5
6
|
import { ComponentsList } from './components-list';
|
|
6
7
|
import { SearchProvider } from './search-provider';
|
|
7
8
|
|
|
9
|
+
const ComponentsContent = () => {
|
|
10
|
+
const { components, isLoading } = useComponents();
|
|
11
|
+
const hasComponents = ! isLoading && components.length > 0;
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<>
|
|
15
|
+
{ hasComponents && <ComponentSearch /> }
|
|
16
|
+
<ComponentsList />
|
|
17
|
+
</>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
20
|
+
|
|
8
21
|
export const Components = () => {
|
|
9
22
|
return (
|
|
10
23
|
<ThemeProvider>
|
|
11
24
|
<SearchProvider localStorageKey="elementor-components-search">
|
|
12
|
-
<
|
|
13
|
-
<ComponentsList />
|
|
25
|
+
<ComponentsContent />
|
|
14
26
|
</SearchProvider>
|
|
15
27
|
</ThemeProvider>
|
|
16
28
|
);
|
|
@@ -1,7 +1,49 @@
|
|
|
1
|
+
import { getV1DocumentsManager, setDocumentModifiedStatus } from '@elementor/editor-documents';
|
|
2
|
+
import { getAllDescendants, type V1Element } from '@elementor/editor-elements';
|
|
1
3
|
import { __dispatch as dispatch } from '@elementor/store';
|
|
2
4
|
|
|
5
|
+
import { COMPONENT_WIDGET_TYPE } from '../../create-component-type';
|
|
3
6
|
import { slice } from '../store';
|
|
4
7
|
|
|
8
|
+
const TITLE_EXTERNAL_CHANGE_COMMAND = 'title_external_change';
|
|
9
|
+
|
|
5
10
|
export const renameComponent = ( componentUid: string, newName: string ) => {
|
|
6
11
|
dispatch( slice.actions.rename( { componentUid, name: newName } ) );
|
|
12
|
+
|
|
13
|
+
setDocumentModifiedStatus( true );
|
|
14
|
+
|
|
15
|
+
refreshComponentInstanceTitles( componentUid );
|
|
7
16
|
};
|
|
17
|
+
|
|
18
|
+
function refreshComponentInstanceTitles( componentUid: string ) {
|
|
19
|
+
const documentContainer = getDocumentContainer();
|
|
20
|
+
|
|
21
|
+
if ( ! documentContainer ) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const componentInstances = findComponentInstancesByUid( documentContainer, componentUid );
|
|
26
|
+
|
|
27
|
+
componentInstances.forEach( ( element ) => {
|
|
28
|
+
element.model.trigger?.( TITLE_EXTERNAL_CHANGE_COMMAND );
|
|
29
|
+
} );
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function getDocumentContainer(): V1Element | undefined {
|
|
33
|
+
const documentsManager = getV1DocumentsManager();
|
|
34
|
+
|
|
35
|
+
return documentsManager?.getCurrent()?.container as V1Element | undefined;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function findComponentInstancesByUid( documentContainer: V1Element, componentUid: string ): V1Element[] {
|
|
39
|
+
const allDescendants = getAllDescendants( documentContainer );
|
|
40
|
+
|
|
41
|
+
return allDescendants.filter( ( element ) => {
|
|
42
|
+
const widgetType = element.model.get( 'widgetType' );
|
|
43
|
+
const editorSettings = element.model.get( 'editor_settings' );
|
|
44
|
+
|
|
45
|
+
const isMatch = widgetType === COMPONENT_WIDGET_TYPE && editorSettings?.component_uid === componentUid;
|
|
46
|
+
|
|
47
|
+
return isMatch;
|
|
48
|
+
} );
|
|
49
|
+
}
|