@elementor/editor-components 4.0.0-manual → 4.0.1
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 +1422 -1
- package/dist/index.d.ts +1422 -1
- package/dist/index.js +2096 -4814
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2028 -4837
- package/dist/index.mjs.map +1 -1
- package/package.json +23 -23
- package/src/components/components-tab/components-list.tsx +92 -4
- package/src/components/components-tab/components-pro-notification.tsx +9 -15
- package/src/components/components-tab/components-update-notification.tsx +13 -0
- package/src/components/components-tab/components.tsx +52 -3
- package/src/components/components-tab/loading-components.tsx +26 -14
- package/src/components/components-update-alert.tsx +40 -0
- package/src/components/components-upgrade-alert.tsx +39 -0
- package/src/components/detach-instance-confirmation-dialog.tsx +50 -0
- package/src/components/instance-editing-panel/detach-action.tsx +76 -0
- package/src/components/instance-editing-panel/empty-state.tsx +9 -2
- package/src/components/instance-editing-panel/instance-editing-panel.tsx +34 -6
- package/src/components/instance-editing-panel/override-prop-control.tsx +14 -6
- package/src/components/instance-editing-panel/use-instance-panel-data.ts +2 -2
- package/src/components/instance-editing-panel/utils/correct-exposed-empty-override.ts +28 -0
- package/src/consts.ts +1 -0
- package/src/create-component-type.ts +130 -29
- package/src/index.ts +92 -0
- package/src/init.ts +6 -4
- package/src/store/actions/update-overridable-prop.ts +4 -10
- package/src/store/dispatchers.ts +63 -0
- package/src/store/extensible-slice.ts +168 -0
- package/src/store/selectors.ts +53 -0
- package/src/store/store-types.ts +48 -0
- package/src/store/store.ts +7 -169
- package/src/sync/publish-draft-components-in-page-before-save.ts +42 -1
- package/src/types.ts +1 -1
- package/src/utils/detach-component-instance/detach-component-instance.ts +172 -0
- package/src/utils/detach-component-instance/index.ts +1 -0
- package/src/utils/detach-component-instance/regenerate-local-style-ids.ts +53 -0
- package/src/utils/detach-component-instance/resolve-detached-instance.ts +94 -0
- package/src/utils/detach-component-instance/resolve-overridable-settings.ts +121 -0
- package/src/utils/is-component-instance.ts +1 -1
- package/src/utils/is-pro-components-supported.ts +11 -0
- package/src/utils/tracking.ts +2 -1
- package/src/extended/components/component-introduction.tsx +0 -77
- package/src/extended/components/component-panel-header/component-badge.tsx +0 -73
- package/src/extended/components/component-panel-header/component-panel-header.tsx +0 -98
- package/src/extended/components/component-properties-panel/component-properties-panel-content.tsx +0 -176
- package/src/extended/components/component-properties-panel/component-properties-panel.tsx +0 -43
- package/src/extended/components/component-properties-panel/properties-empty-state.tsx +0 -51
- package/src/extended/components/component-properties-panel/properties-group.tsx +0 -196
- package/src/extended/components/component-properties-panel/property-item.tsx +0 -124
- package/src/extended/components/component-properties-panel/sortable.tsx +0 -92
- package/src/extended/components/component-properties-panel/use-current-editable-item.ts +0 -73
- package/src/extended/components/component-properties-panel/utils/generate-unique-label.ts +0 -21
- package/src/extended/components/component-properties-panel/utils/validate-group-label.ts +0 -24
- package/src/extended/components/components-tab/component-item.tsx +0 -180
- package/src/extended/components/components-tab/components.tsx +0 -58
- package/src/extended/components/components-tab/delete-confirmation-dialog.tsx +0 -26
- package/src/extended/components/create-component-form/create-component-form.tsx +0 -282
- package/src/extended/components/create-component-form/hooks/use-form.ts +0 -72
- package/src/extended/components/create-component-form/utils/get-component-event-data.ts +0 -54
- package/src/extended/components/edit-component/component-modal.tsx +0 -133
- package/src/extended/components/edit-component/edit-component.tsx +0 -166
- package/src/extended/components/edit-component/use-canvas-document.ts +0 -9
- package/src/extended/components/edit-component/use-element-rect.ts +0 -81
- package/src/extended/components/instance-editing-panel/instance-editing-panel.tsx +0 -60
- package/src/extended/components/overridable-props/indicator.tsx +0 -83
- package/src/extended/components/overridable-props/overridable-prop-control.tsx +0 -127
- package/src/extended/components/overridable-props/overridable-prop-form.tsx +0 -135
- package/src/extended/components/overridable-props/overridable-prop-indicator.tsx +0 -138
- package/src/extended/components/overridable-props/utils/validate-prop-label.ts +0 -38
- package/src/extended/consts.ts +0 -3
- package/src/extended/hooks/use-navigate-back.ts +0 -24
- package/src/extended/init.ts +0 -104
- package/src/extended/mcp/index.ts +0 -14
- package/src/extended/mcp/save-as-component-tool.ts +0 -436
- package/src/extended/store/actions/add-overridable-group.ts +0 -59
- package/src/extended/store/actions/archive-component.ts +0 -19
- package/src/extended/store/actions/create-unpublished-component.ts +0 -102
- package/src/extended/store/actions/delete-overridable-group.ts +0 -38
- package/src/extended/store/actions/delete-overridable-prop.ts +0 -70
- package/src/extended/store/actions/rename-component.ts +0 -49
- package/src/extended/store/actions/rename-overridable-group.ts +0 -39
- package/src/extended/store/actions/reorder-group-props.ts +0 -43
- package/src/extended/store/actions/reorder-overridable-groups.ts +0 -30
- package/src/extended/store/actions/reset-sanitized-components.ts +0 -7
- package/src/extended/store/actions/set-overridable-prop.ts +0 -117
- package/src/extended/store/actions/update-component-sanitized-attribute.ts +0 -8
- package/src/extended/store/actions/update-current-component.ts +0 -21
- package/src/extended/store/actions/update-overridable-prop-params.ts +0 -58
- package/src/extended/store/utils/groups-transformers.ts +0 -187
- package/src/extended/sync/before-save.ts +0 -52
- package/src/extended/sync/cleanup-overridable-props-on-delete.ts +0 -85
- package/src/extended/sync/create-components-before-save.ts +0 -113
- package/src/extended/sync/handle-component-edit-mode-container.ts +0 -114
- package/src/extended/sync/prevent-non-atomic-nesting.ts +0 -198
- package/src/extended/sync/revert-overridables-on-copy-or-duplicate.ts +0 -66
- package/src/extended/sync/sanitize-overridable-props.ts +0 -32
- package/src/extended/sync/set-component-overridable-props-settings-before-save.ts +0 -23
- package/src/extended/sync/update-archived-component-before-save.ts +0 -32
- package/src/extended/sync/update-component-title-before-save.ts +0 -19
- package/src/extended/utils/component-form-schema.ts +0 -32
- package/src/extended/utils/component-name-validation.ts +0 -27
- package/src/extended/utils/create-component-model.ts +0 -28
- package/src/extended/utils/get-container-for-new-element.ts +0 -49
- package/src/extended/utils/is-editing-component.ts +0 -13
- package/src/extended/utils/replace-element-with-component.ts +0 -11
- package/src/extended/utils/revert-overridable-settings.ts +0 -207
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-components",
|
|
3
3
|
"description": "Elementor editor components",
|
|
4
|
-
"version": "4.0.
|
|
4
|
+
"version": "4.0.1",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "Elementor Team",
|
|
7
7
|
"homepage": "https://elementor.com/",
|
|
@@ -40,31 +40,31 @@
|
|
|
40
40
|
"dev": "tsup --config=../../tsup.dev.ts"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@elementor/editor": "4.0.
|
|
44
|
-
"@elementor/editor-canvas": "4.0.
|
|
45
|
-
"@elementor/editor-controls": "4.0.
|
|
46
|
-
"@elementor/editor-documents": "4.0.
|
|
47
|
-
"@elementor/editor-editing-panel": "4.0.
|
|
48
|
-
"@elementor/editor-elements": "4.0.
|
|
49
|
-
"@elementor/editor-elements-panel": "4.0.
|
|
50
|
-
"@elementor/editor-mcp": "4.0.
|
|
51
|
-
"@elementor/editor-templates": "4.0.
|
|
52
|
-
"@elementor/editor-panels": "4.0.
|
|
53
|
-
"@elementor/editor-props": "4.0.
|
|
54
|
-
"@elementor/editor-styles-repository": "4.0.
|
|
55
|
-
"@elementor/editor-ui": "4.0.
|
|
56
|
-
"@elementor/editor-v1-adapters": "4.0.
|
|
57
|
-
"@elementor/http-client": "4.0.
|
|
43
|
+
"@elementor/editor": "4.0.1",
|
|
44
|
+
"@elementor/editor-canvas": "4.0.1",
|
|
45
|
+
"@elementor/editor-controls": "4.0.1",
|
|
46
|
+
"@elementor/editor-documents": "4.0.1",
|
|
47
|
+
"@elementor/editor-editing-panel": "4.0.1",
|
|
48
|
+
"@elementor/editor-elements": "4.0.1",
|
|
49
|
+
"@elementor/editor-elements-panel": "4.0.1",
|
|
50
|
+
"@elementor/editor-mcp": "4.0.1",
|
|
51
|
+
"@elementor/editor-templates": "4.0.1",
|
|
52
|
+
"@elementor/editor-panels": "4.0.1",
|
|
53
|
+
"@elementor/editor-props": "4.0.1",
|
|
54
|
+
"@elementor/editor-styles-repository": "4.0.1",
|
|
55
|
+
"@elementor/editor-ui": "4.0.1",
|
|
56
|
+
"@elementor/editor-v1-adapters": "4.0.1",
|
|
57
|
+
"@elementor/http-client": "4.0.1",
|
|
58
58
|
"@elementor/icons": "^1.68.0",
|
|
59
|
-
"@elementor/events": "4.0.
|
|
60
|
-
"@elementor/query": "4.0.
|
|
61
|
-
"@elementor/schema": "4.0.
|
|
62
|
-
"@elementor/store": "4.0.
|
|
59
|
+
"@elementor/events": "4.0.1",
|
|
60
|
+
"@elementor/query": "4.0.1",
|
|
61
|
+
"@elementor/schema": "4.0.1",
|
|
62
|
+
"@elementor/store": "4.0.1",
|
|
63
63
|
"@elementor/ui": "1.36.17",
|
|
64
|
-
"@elementor/utils": "4.0.
|
|
64
|
+
"@elementor/utils": "4.0.1",
|
|
65
65
|
"@wordpress/i18n": "^5.13.0",
|
|
66
|
-
"@elementor/editor-notifications": "4.0.
|
|
67
|
-
"@elementor/editor-current-user": "4.0.
|
|
66
|
+
"@elementor/editor-notifications": "4.0.1",
|
|
67
|
+
"@elementor/editor-current-user": "4.0.1"
|
|
68
68
|
},
|
|
69
69
|
"peerDependencies": {
|
|
70
70
|
"react": "^18.3.1",
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { ComponentsIcon } from '@elementor/icons';
|
|
3
|
-
import { Box, Divider, Link, List, Stack, Typography } from '@elementor/ui';
|
|
2
|
+
import { ComponentsIcon, CrownFilledIcon } from '@elementor/icons';
|
|
3
|
+
import { Box, Button, Divider, Link, List, Stack, Typography } from '@elementor/ui';
|
|
4
4
|
import { __ } from '@wordpress/i18n';
|
|
5
5
|
|
|
6
6
|
import { useComponents } from '../../hooks/use-components';
|
|
7
7
|
import { useComponentsPermissions } from '../../hooks/use-components-permissions';
|
|
8
|
+
import { isProComponentsSupported, isProOutdatedForComponents } from '../../utils/is-pro-components-supported';
|
|
8
9
|
import { ComponentItem } from './components-item';
|
|
9
10
|
import { LoadingComponents } from './loading-components';
|
|
10
11
|
import { useSearch } from './search-provider';
|
|
11
12
|
|
|
12
13
|
const LEARN_MORE_URL = 'http://go.elementor.com/components-guide-article';
|
|
14
|
+
const UPGRADE_URL = 'https://go.elementor.com/go-pro-components/';
|
|
15
|
+
const UPDATE_PLUGINS_URL = '/wp-admin/plugins.php';
|
|
13
16
|
|
|
14
17
|
// Override legacy panel CSS reset that sets h1-h6 to font-size:100% and font-weight:normal.
|
|
15
18
|
// See: assets/dev/scss/editor/panel/_reset.scss (applied via :where() selector in panel.scss).
|
|
@@ -28,7 +31,15 @@ export function ComponentsList() {
|
|
|
28
31
|
const isEmpty = ! components?.length;
|
|
29
32
|
|
|
30
33
|
if ( isEmpty ) {
|
|
31
|
-
|
|
34
|
+
if ( searchValue.length ) {
|
|
35
|
+
return <EmptySearchResult />;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if ( isProOutdatedForComponents() ) {
|
|
39
|
+
return <ProOutdatedEmptyState />;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return isProComponentsSupported() ? <EmptyState /> : <ProUpgradeEmptyState />;
|
|
32
43
|
}
|
|
33
44
|
|
|
34
45
|
return (
|
|
@@ -40,7 +51,84 @@ export function ComponentsList() {
|
|
|
40
51
|
);
|
|
41
52
|
}
|
|
42
53
|
|
|
43
|
-
|
|
54
|
+
const ProUpgradeEmptyState = () => {
|
|
55
|
+
return (
|
|
56
|
+
<Stack
|
|
57
|
+
alignItems="center"
|
|
58
|
+
justifyContent="start"
|
|
59
|
+
height="100%"
|
|
60
|
+
sx={ { px: 2, py: 4 } }
|
|
61
|
+
gap={ 2 }
|
|
62
|
+
overflow="hidden"
|
|
63
|
+
>
|
|
64
|
+
<Stack alignItems="center" gap={ 1 }>
|
|
65
|
+
<ComponentsIcon fontSize="large" sx={ { color: 'text.secondary' } } />
|
|
66
|
+
|
|
67
|
+
<Typography align="center" variant="subtitle2" color="text.secondary" sx={ SUBTITLE_OVERRIDE_SX }>
|
|
68
|
+
{ __( 'Create Reusable Components', 'elementor' ) }
|
|
69
|
+
</Typography>
|
|
70
|
+
|
|
71
|
+
<Typography align="center" variant="caption" color="secondary" sx={ { maxWidth: 200 } }>
|
|
72
|
+
{ __( 'Create design elements that sync across your entire site.', 'elementor' ) }
|
|
73
|
+
</Typography>
|
|
74
|
+
</Stack>
|
|
75
|
+
|
|
76
|
+
<Button
|
|
77
|
+
variant="contained"
|
|
78
|
+
color="promotion"
|
|
79
|
+
size="small"
|
|
80
|
+
startIcon={ <CrownFilledIcon /> }
|
|
81
|
+
href={ UPGRADE_URL }
|
|
82
|
+
target="_blank"
|
|
83
|
+
rel="noopener noreferrer"
|
|
84
|
+
>
|
|
85
|
+
{ __( 'Upgrade now', 'elementor' ) }
|
|
86
|
+
</Button>
|
|
87
|
+
</Stack>
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const ProOutdatedEmptyState = () => {
|
|
92
|
+
return (
|
|
93
|
+
<Stack
|
|
94
|
+
alignItems="center"
|
|
95
|
+
justifyContent="start"
|
|
96
|
+
height="100%"
|
|
97
|
+
sx={ { px: 2, py: 4, maxWidth: 268, m: 'auto' } }
|
|
98
|
+
gap={ 2 }
|
|
99
|
+
overflow="hidden"
|
|
100
|
+
>
|
|
101
|
+
<Stack alignItems="center" gap={ 1 }>
|
|
102
|
+
<ComponentsIcon fontSize="large" sx={ { color: 'text.secondary' } } />
|
|
103
|
+
|
|
104
|
+
<Typography align="center" variant="subtitle2" color="text.secondary" sx={ SUBTITLE_OVERRIDE_SX }>
|
|
105
|
+
{ __( 'Create Reusable Components', 'elementor' ) }
|
|
106
|
+
</Typography>
|
|
107
|
+
|
|
108
|
+
<Typography align="center" variant="caption" color="secondary">
|
|
109
|
+
{ __( 'Create design elements that sync across your entire site.', 'elementor' ) }
|
|
110
|
+
</Typography>
|
|
111
|
+
|
|
112
|
+
<Typography align="center" variant="caption" color="secondary" sx={ { mt: 1 } }>
|
|
113
|
+
{ __( 'To create components, update Elementor Pro to the latest version.', 'elementor' ) }
|
|
114
|
+
</Typography>
|
|
115
|
+
</Stack>
|
|
116
|
+
|
|
117
|
+
<Button
|
|
118
|
+
variant="text"
|
|
119
|
+
color="info"
|
|
120
|
+
size="small"
|
|
121
|
+
href={ UPDATE_PLUGINS_URL }
|
|
122
|
+
target="_blank"
|
|
123
|
+
rel="noopener noreferrer"
|
|
124
|
+
>
|
|
125
|
+
{ __( 'Update Elementor Pro', 'elementor' ) }
|
|
126
|
+
</Button>
|
|
127
|
+
</Stack>
|
|
128
|
+
);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const EmptyState = () => {
|
|
44
132
|
const { canCreate } = useComponentsPermissions();
|
|
45
133
|
|
|
46
134
|
return (
|
|
@@ -1,22 +1,16 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { InfoAlert } from '@elementor/editor-ui';
|
|
3
|
-
import { Box, Typography } from '@elementor/ui';
|
|
4
2
|
import { __ } from '@wordpress/i18n';
|
|
5
3
|
|
|
4
|
+
import { ComponentsUpgradeAlert } from '../components-upgrade-alert';
|
|
5
|
+
|
|
6
|
+
export const UPGRADE_URL = 'https://go.elementor.com/go-pro-components-exist-footer/';
|
|
7
|
+
|
|
6
8
|
export function ComponentsProNotification() {
|
|
7
9
|
return (
|
|
8
|
-
<
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
</Typography>{ ' ' }
|
|
14
|
-
{ __(
|
|
15
|
-
'Soon Components will be part of the Pro subscription, but what you create now will remain on your site.',
|
|
16
|
-
'elementor'
|
|
17
|
-
) }
|
|
18
|
-
</Typography>
|
|
19
|
-
</InfoAlert>
|
|
20
|
-
</Box>
|
|
10
|
+
<ComponentsUpgradeAlert
|
|
11
|
+
title={ __( 'Create new components', 'elementor' ) }
|
|
12
|
+
description={ __( 'Creating new components requires an active Pro subscription.', 'elementor' ) }
|
|
13
|
+
upgradeUrl={ UPGRADE_URL }
|
|
14
|
+
/>
|
|
21
15
|
);
|
|
22
16
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { __ } from '@wordpress/i18n';
|
|
3
|
+
|
|
4
|
+
import { ComponentsUpdateAlert } from '../components-update-alert';
|
|
5
|
+
|
|
6
|
+
export function ComponentsUpdateNotification() {
|
|
7
|
+
return (
|
|
8
|
+
<ComponentsUpdateAlert
|
|
9
|
+
title={ __( 'Create new Components', 'elementor' ) }
|
|
10
|
+
description={ __( 'To create new components, update Elementor Pro to the latest version.', 'elementor' ) }
|
|
11
|
+
/>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
@@ -1,22 +1,71 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { useLayoutEffect } from 'react';
|
|
2
3
|
import { ThemeProvider } from '@elementor/editor-ui';
|
|
4
|
+
import { Stack } from '@elementor/ui';
|
|
3
5
|
|
|
4
6
|
import { useComponents } from '../../hooks/use-components';
|
|
7
|
+
import { isProComponentsSupported, isProOutdatedForComponents } from '../../utils/is-pro-components-supported';
|
|
5
8
|
import { ComponentSearch } from './component-search';
|
|
6
9
|
import { ComponentsList } from './components-list';
|
|
7
10
|
import { ComponentsProNotification } from './components-pro-notification';
|
|
11
|
+
import { ComponentsUpdateNotification } from './components-update-notification';
|
|
8
12
|
import { SearchProvider } from './search-provider';
|
|
9
13
|
|
|
14
|
+
const FULL_HEIGHT_STYLE_ID = 'components-full-height-panel';
|
|
15
|
+
|
|
16
|
+
const FULL_HEIGHT_CSS = `
|
|
17
|
+
#elementor-panel-page-elements {
|
|
18
|
+
display: flex;
|
|
19
|
+
flex-direction: column;
|
|
20
|
+
height: 100%;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
#elementor-panel-elements {
|
|
24
|
+
display: flex;
|
|
25
|
+
flex-direction: column;
|
|
26
|
+
flex: 1;
|
|
27
|
+
min-height: 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#elementor-panel-elements-wrapper {
|
|
31
|
+
display: flex;
|
|
32
|
+
flex-direction: column;
|
|
33
|
+
flex: 1;
|
|
34
|
+
min-height: 0;
|
|
35
|
+
}
|
|
36
|
+
`;
|
|
37
|
+
|
|
38
|
+
const useFullHeightPanel = () => {
|
|
39
|
+
useLayoutEffect( () => {
|
|
40
|
+
let style = document.getElementById( FULL_HEIGHT_STYLE_ID );
|
|
41
|
+
|
|
42
|
+
if ( ! style ) {
|
|
43
|
+
style = document.createElement( 'style' );
|
|
44
|
+
style.id = FULL_HEIGHT_STYLE_ID;
|
|
45
|
+
style.textContent = FULL_HEIGHT_CSS;
|
|
46
|
+
document.head.appendChild( style );
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return () => {
|
|
50
|
+
document.getElementById( FULL_HEIGHT_STYLE_ID )?.remove();
|
|
51
|
+
};
|
|
52
|
+
}, [] );
|
|
53
|
+
};
|
|
54
|
+
|
|
10
55
|
const ComponentsContent = () => {
|
|
11
56
|
const { components, isLoading } = useComponents();
|
|
12
57
|
const hasComponents = ! isLoading && components.length > 0;
|
|
58
|
+
const showProNotification = ! isProComponentsSupported() && hasComponents;
|
|
59
|
+
const isOutdated = isProOutdatedForComponents();
|
|
60
|
+
|
|
61
|
+
useFullHeightPanel();
|
|
13
62
|
|
|
14
63
|
return (
|
|
15
|
-
|
|
64
|
+
<Stack justifyContent="space-between" sx={ { flex: 1, minHeight: 0 } }>
|
|
16
65
|
{ hasComponents && <ComponentSearch /> }
|
|
17
|
-
{ hasComponents && <ComponentsProNotification /> }
|
|
18
66
|
<ComponentsList />
|
|
19
|
-
|
|
67
|
+
{ showProNotification && ( isOutdated ? <ComponentsUpdateNotification /> : <ComponentsProNotification /> ) }
|
|
68
|
+
</Stack>
|
|
20
69
|
);
|
|
21
70
|
};
|
|
22
71
|
|
|
@@ -1,41 +1,53 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { Box,
|
|
2
|
+
import { Box, Skeleton, Stack } from '@elementor/ui';
|
|
3
3
|
|
|
4
|
-
const ROWS = Array.from( { length:
|
|
4
|
+
const ROWS = Array.from( { length: 3 }, ( _, index ) => index );
|
|
5
|
+
|
|
6
|
+
const STAGGER_DELAY_MS = 80;
|
|
5
7
|
|
|
6
8
|
export const LoadingComponents = () => {
|
|
7
9
|
return (
|
|
8
10
|
<Stack
|
|
9
11
|
aria-label="Loading components"
|
|
10
|
-
gap={ 1 }
|
|
12
|
+
gap={ 1.5 }
|
|
11
13
|
sx={ {
|
|
12
14
|
pointerEvents: 'none',
|
|
13
15
|
position: 'relative',
|
|
14
16
|
maxHeight: '300px',
|
|
15
17
|
overflow: 'hidden',
|
|
18
|
+
px: 1,
|
|
16
19
|
'&:after': {
|
|
17
20
|
position: 'absolute',
|
|
18
|
-
|
|
21
|
+
bottom: 0,
|
|
19
22
|
content: '""',
|
|
20
23
|
left: 0,
|
|
21
24
|
width: '100%',
|
|
22
|
-
height: '
|
|
23
|
-
background: 'linear-gradient(to top, white, transparent)',
|
|
25
|
+
height: '40%',
|
|
24
26
|
pointerEvents: 'none',
|
|
27
|
+
zIndex: 1,
|
|
25
28
|
},
|
|
26
29
|
} }
|
|
27
30
|
>
|
|
28
31
|
{ ROWS.map( ( row ) => (
|
|
29
|
-
<
|
|
32
|
+
<Box
|
|
30
33
|
key={ row }
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
display="flex"
|
|
35
|
+
alignItems="center"
|
|
36
|
+
gap={ 1.5 }
|
|
37
|
+
sx={ {
|
|
38
|
+
py: 0.75,
|
|
39
|
+
px: 1.5,
|
|
40
|
+
opacity: 0,
|
|
41
|
+
animation: `e-loading-fade-in 0.4s ease-out ${ row * STAGGER_DELAY_MS }ms forwards`,
|
|
42
|
+
'@keyframes e-loading-fade-in': {
|
|
43
|
+
from: { opacity: 0, transform: 'translateY(4px)' },
|
|
44
|
+
to: { opacity: 1, transform: 'translateY(0)' },
|
|
45
|
+
},
|
|
46
|
+
} }
|
|
33
47
|
>
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
</Box>
|
|
38
|
-
</ListItemButton>
|
|
48
|
+
<Skeleton animation="wave" variant="rounded" width={ 24 } height={ 24 } />
|
|
49
|
+
<Skeleton animation="wave" variant="rounded" width="60%" height={ 14 } />
|
|
50
|
+
</Box>
|
|
39
51
|
) ) }
|
|
40
52
|
</Stack>
|
|
41
53
|
);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { InfoCircleFilledIcon } from '@elementor/icons';
|
|
3
|
+
import { Alert, AlertAction, AlertTitle, Box, Typography } from '@elementor/ui';
|
|
4
|
+
import { __ } from '@wordpress/i18n';
|
|
5
|
+
|
|
6
|
+
const UPDATE_PLUGINS_URL = '/wp-admin/plugins.php';
|
|
7
|
+
|
|
8
|
+
interface ComponentsUpdateAlertProps {
|
|
9
|
+
title: string;
|
|
10
|
+
description: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function ComponentsUpdateAlert( { title, description }: ComponentsUpdateAlertProps ) {
|
|
14
|
+
return (
|
|
15
|
+
<Box sx={ { mt: 'auto', position: 'sticky', bottom: 0 } }>
|
|
16
|
+
<Alert
|
|
17
|
+
variant="standard"
|
|
18
|
+
color="info"
|
|
19
|
+
icon={ <InfoCircleFilledIcon fontSize="tiny" /> }
|
|
20
|
+
role="status"
|
|
21
|
+
size="small"
|
|
22
|
+
action={
|
|
23
|
+
<AlertAction
|
|
24
|
+
variant="contained"
|
|
25
|
+
color="info"
|
|
26
|
+
href={ UPDATE_PLUGINS_URL }
|
|
27
|
+
target="_blank"
|
|
28
|
+
rel="noopener noreferrer"
|
|
29
|
+
>
|
|
30
|
+
{ __( 'Upgrade Now', 'elementor' ) }
|
|
31
|
+
</AlertAction>
|
|
32
|
+
}
|
|
33
|
+
sx={ { m: 2, mt: 1 } }
|
|
34
|
+
>
|
|
35
|
+
<AlertTitle>{ title }</AlertTitle>
|
|
36
|
+
<Typography variant="caption">{ description }</Typography>
|
|
37
|
+
</Alert>
|
|
38
|
+
</Box>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { CrownFilledIcon } from '@elementor/icons';
|
|
3
|
+
import { Alert, AlertAction, AlertTitle, Box, Typography } from '@elementor/ui';
|
|
4
|
+
import { __ } from '@wordpress/i18n';
|
|
5
|
+
|
|
6
|
+
interface ComponentsUpgradeAlertProps {
|
|
7
|
+
title: string;
|
|
8
|
+
description: string;
|
|
9
|
+
upgradeUrl: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function ComponentsUpgradeAlert( { title, description, upgradeUrl }: ComponentsUpgradeAlertProps ) {
|
|
13
|
+
return (
|
|
14
|
+
<Box sx={ { mt: 'auto', position: 'sticky', bottom: 0 } }>
|
|
15
|
+
<Alert
|
|
16
|
+
variant="standard"
|
|
17
|
+
color="promotion"
|
|
18
|
+
icon={ <CrownFilledIcon fontSize="tiny" /> }
|
|
19
|
+
role="status"
|
|
20
|
+
size="small"
|
|
21
|
+
action={
|
|
22
|
+
<AlertAction
|
|
23
|
+
variant="contained"
|
|
24
|
+
color="promotion"
|
|
25
|
+
href={ upgradeUrl }
|
|
26
|
+
target="_blank"
|
|
27
|
+
rel="noopener noreferrer"
|
|
28
|
+
>
|
|
29
|
+
{ __( 'Upgrade now', 'elementor' ) }
|
|
30
|
+
</AlertAction>
|
|
31
|
+
}
|
|
32
|
+
sx={ { m: 2, mt: 1 } }
|
|
33
|
+
>
|
|
34
|
+
<AlertTitle>{ title }</AlertTitle>
|
|
35
|
+
<Typography variant="caption">{ description }</Typography>
|
|
36
|
+
</Alert>
|
|
37
|
+
</Box>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { closeDialog, ConfirmationDialog, openDialog } from '@elementor/editor-ui';
|
|
3
|
+
import { AlertTriangleFilledIcon } from '@elementor/icons';
|
|
4
|
+
import { __ } from '@wordpress/i18n';
|
|
5
|
+
|
|
6
|
+
type DetachInstanceConfirmationDialogProps = {
|
|
7
|
+
open: boolean;
|
|
8
|
+
onClose: () => void;
|
|
9
|
+
onConfirm: () => void;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export function DetachInstanceConfirmationDialog( {
|
|
13
|
+
open,
|
|
14
|
+
onClose,
|
|
15
|
+
onConfirm,
|
|
16
|
+
}: DetachInstanceConfirmationDialogProps ) {
|
|
17
|
+
return (
|
|
18
|
+
<ConfirmationDialog open={ open } onClose={ onClose }>
|
|
19
|
+
<ConfirmationDialog.Title icon={ AlertTriangleFilledIcon } iconColor="secondary">
|
|
20
|
+
{ __( 'Detach from Component?', 'elementor' ) }
|
|
21
|
+
</ConfirmationDialog.Title>
|
|
22
|
+
<ConfirmationDialog.Content>
|
|
23
|
+
<ConfirmationDialog.ContentText>
|
|
24
|
+
{ __(
|
|
25
|
+
'Detaching this instance will break its link to the Component. Changes to the Component will no longer apply. Continue?',
|
|
26
|
+
'elementor'
|
|
27
|
+
) }
|
|
28
|
+
</ConfirmationDialog.ContentText>
|
|
29
|
+
</ConfirmationDialog.Content>
|
|
30
|
+
<ConfirmationDialog.Actions
|
|
31
|
+
onClose={ onClose }
|
|
32
|
+
onConfirm={ onConfirm }
|
|
33
|
+
confirmLabel={ __( 'Detach', 'elementor' ) }
|
|
34
|
+
color="primary"
|
|
35
|
+
/>
|
|
36
|
+
</ConfirmationDialog>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Used imperatively from the context menu (Marionette view).
|
|
41
|
+
export function openDetachConfirmDialog( onConfirm: () => void ) {
|
|
42
|
+
const handleConfirm = () => {
|
|
43
|
+
closeDialog();
|
|
44
|
+
onConfirm();
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
openDialog( {
|
|
48
|
+
component: <DetachInstanceConfirmationDialog open onClose={ closeDialog } onConfirm={ handleConfirm } />,
|
|
49
|
+
} );
|
|
50
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { notify } from '@elementor/editor-notifications';
|
|
4
|
+
import { DetachIcon } from '@elementor/icons';
|
|
5
|
+
import { __ } from '@wordpress/i18n';
|
|
6
|
+
|
|
7
|
+
import { type ExtendedWindow } from '../../types';
|
|
8
|
+
import { detachComponentInstance } from '../../utils/detach-component-instance';
|
|
9
|
+
import { DetachInstanceConfirmationDialog } from '../detach-instance-confirmation-dialog';
|
|
10
|
+
import { EditComponentAction } from './instance-panel-header';
|
|
11
|
+
|
|
12
|
+
export const DetachAction = ( {
|
|
13
|
+
componentInstanceId,
|
|
14
|
+
componentId,
|
|
15
|
+
}: {
|
|
16
|
+
componentInstanceId: string;
|
|
17
|
+
componentId: number;
|
|
18
|
+
} ) => {
|
|
19
|
+
const [ isDetachDialogOpen, setIsDetachDialogOpen ] = useState( false );
|
|
20
|
+
|
|
21
|
+
const handleDetachConfirm = async () => {
|
|
22
|
+
setIsDetachDialogOpen( false );
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
await detachComponentInstance( {
|
|
26
|
+
instanceId: componentInstanceId,
|
|
27
|
+
componentId,
|
|
28
|
+
trackingInfo: getDetachTrackingInfo(),
|
|
29
|
+
} );
|
|
30
|
+
} catch {
|
|
31
|
+
notify( {
|
|
32
|
+
type: 'error',
|
|
33
|
+
message: __( 'Failed to detach component instance.', 'elementor' ),
|
|
34
|
+
id: 'detach-component-instance-failed',
|
|
35
|
+
} );
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const handleDetachCancel = () => {
|
|
40
|
+
setIsDetachDialogOpen( false );
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const handleDetachClick = () => {
|
|
44
|
+
setIsDetachDialogOpen( true );
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const detachLabel = __( 'Detach from Component', 'elementor' );
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<>
|
|
51
|
+
<EditComponentAction label={ detachLabel } icon={ DetachIcon } onClick={ handleDetachClick } />
|
|
52
|
+
<DetachInstanceConfirmationDialog
|
|
53
|
+
open={ isDetachDialogOpen }
|
|
54
|
+
onClose={ handleDetachCancel }
|
|
55
|
+
onConfirm={ handleDetachConfirm }
|
|
56
|
+
/>
|
|
57
|
+
</>
|
|
58
|
+
);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
function getDetachTrackingInfo() {
|
|
62
|
+
const extendedWindow = window as unknown as ExtendedWindow;
|
|
63
|
+
const config = extendedWindow?.elementorCommon?.eventsManager?.config;
|
|
64
|
+
|
|
65
|
+
if ( ! config ) {
|
|
66
|
+
return {
|
|
67
|
+
location: '',
|
|
68
|
+
trigger: '',
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
location: ( config.locations.components as Record< string, string > ).instanceEditingPanel,
|
|
74
|
+
trigger: config.triggers.click,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
@@ -34,8 +34,15 @@ export const EmptyState = ( { onEditComponent }: { onEditComponent?: () => void
|
|
|
34
34
|
<Typography align="center" variant="caption" maxWidth="170px">
|
|
35
35
|
{ message }
|
|
36
36
|
</Typography>
|
|
37
|
-
{ canEdit &&
|
|
38
|
-
<Button
|
|
37
|
+
{ canEdit && (
|
|
38
|
+
<Button
|
|
39
|
+
variant="outlined"
|
|
40
|
+
color="secondary"
|
|
41
|
+
size="small"
|
|
42
|
+
sx={ { mt: 1 } }
|
|
43
|
+
disabled={ ! onEditComponent }
|
|
44
|
+
onClick={ onEditComponent }
|
|
45
|
+
>
|
|
39
46
|
<PencilIcon fontSize="small" />
|
|
40
47
|
{ __( 'Edit component', 'elementor' ) }
|
|
41
48
|
</Button>
|
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { PencilIcon } from '@elementor/icons';
|
|
3
|
-
import { Box } from '@elementor/ui';
|
|
3
|
+
import { Box, Stack } from '@elementor/ui';
|
|
4
4
|
import { __ } from '@wordpress/i18n';
|
|
5
5
|
|
|
6
|
+
import { useComponentsPermissions } from '../../hooks/use-components-permissions';
|
|
6
7
|
import { ComponentInstanceProvider } from '../../provider/component-instance-context';
|
|
8
|
+
import { isProComponentsSupported, isProOutdatedForComponents } from '../../utils/is-pro-components-supported';
|
|
9
|
+
import { ComponentsUpdateAlert } from '../components-update-alert';
|
|
10
|
+
import { ComponentsUpgradeAlert } from '../components-upgrade-alert';
|
|
11
|
+
import { DetachAction } from './detach-action';
|
|
7
12
|
import { EmptyState } from './empty-state';
|
|
8
13
|
import { InstancePanelBody } from './instance-panel-body';
|
|
9
14
|
import { EditComponentAction, InstancePanelHeader } from './instance-panel-header';
|
|
10
15
|
import { useInstancePanelData } from './use-instance-panel-data';
|
|
11
16
|
|
|
17
|
+
const EDIT_UPGRADE_URL = 'https://go.elementor.com/go-pro-components-Instance-edit-footer/';
|
|
18
|
+
|
|
12
19
|
export function InstanceEditingPanel() {
|
|
20
|
+
const { canEdit } = useComponentsPermissions();
|
|
13
21
|
const data = useInstancePanelData();
|
|
14
22
|
|
|
15
23
|
if ( ! data ) {
|
|
@@ -21,17 +29,21 @@ export function InstanceEditingPanel() {
|
|
|
21
29
|
/* translators: %s: component name. */
|
|
22
30
|
const panelTitle = __( 'Edit %s', 'elementor' ).replace( '%s', component.name );
|
|
23
31
|
|
|
32
|
+
const actions = (
|
|
33
|
+
<Stack direction="row" gap={ 0.5 }>
|
|
34
|
+
<DetachAction componentInstanceId={ componentInstanceId } componentId={ componentId } />
|
|
35
|
+
{ canEdit && <EditComponentAction disabled label={ panelTitle } icon={ PencilIcon } /> }
|
|
36
|
+
</Stack>
|
|
37
|
+
);
|
|
38
|
+
|
|
24
39
|
return (
|
|
25
|
-
<Box data-testid="instance-editing-panel">
|
|
40
|
+
<Box data-testid="instance-editing-panel" sx={ { display: 'flex', flexDirection: 'column', height: '100%' } }>
|
|
26
41
|
<ComponentInstanceProvider
|
|
27
42
|
componentId={ componentId }
|
|
28
43
|
overrides={ overrides }
|
|
29
44
|
overridableProps={ overridableProps }
|
|
30
45
|
>
|
|
31
|
-
<InstancePanelHeader
|
|
32
|
-
componentName={ component.name }
|
|
33
|
-
actions={ <EditComponentAction disabled label={ panelTitle } icon={ PencilIcon } /> }
|
|
34
|
-
/>
|
|
46
|
+
<InstancePanelHeader componentName={ component.name } actions={ actions } />
|
|
35
47
|
<InstancePanelBody
|
|
36
48
|
groups={ groups }
|
|
37
49
|
isEmpty={ isEmpty }
|
|
@@ -39,6 +51,22 @@ export function InstanceEditingPanel() {
|
|
|
39
51
|
componentInstanceId={ componentInstanceId }
|
|
40
52
|
/>
|
|
41
53
|
</ComponentInstanceProvider>
|
|
54
|
+
{ ! isProComponentsSupported() &&
|
|
55
|
+
( isProOutdatedForComponents() ? (
|
|
56
|
+
<ComponentsUpdateAlert
|
|
57
|
+
title={ __( 'Edit Component', 'elementor' ) }
|
|
58
|
+
description={ __(
|
|
59
|
+
'To edit components, update Elementor Pro to the latest version.',
|
|
60
|
+
'elementor'
|
|
61
|
+
) }
|
|
62
|
+
/>
|
|
63
|
+
) : (
|
|
64
|
+
<ComponentsUpgradeAlert
|
|
65
|
+
title={ __( 'Edit components', 'elementor' ) }
|
|
66
|
+
description={ __( 'Editing components requires an active Pro subscription.', 'elementor' ) }
|
|
67
|
+
upgradeUrl={ EDIT_UPGRADE_URL }
|
|
68
|
+
/>
|
|
69
|
+
) ) }
|
|
42
70
|
</Box>
|
|
43
71
|
);
|
|
44
72
|
}
|