@elementor/editor-components 4.0.0-682 → 4.0.0-beta5
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 +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +287 -150
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +270 -132
- package/dist/index.mjs.map +1 -1
- package/package.json +23 -23
- package/src/api.ts +8 -7
- package/src/components/components-tab/components-list.tsx +47 -2
- package/src/components/components-tab/components-pro-notification.tsx +1 -1
- package/src/components/components-tab/components-update-notification.tsx +13 -0
- package/src/components/components-tab/components.tsx +5 -4
- package/src/components/components-update-alert.tsx +40 -0
- package/src/components/instance-editing-panel/instance-editing-panel.tsx +19 -10
- package/src/components/instance-editing-panel/override-prop-control.tsx +14 -6
- package/src/components/instance-editing-panel/utils/correct-exposed-empty-override.ts +28 -0
- package/src/create-component-type.ts +45 -7
- package/src/store/actions/load-components-overridable-props.ts +5 -22
- package/src/store/extensible-slice.ts +19 -0
- package/src/sync/publish-draft-components-in-page-before-save.ts +1 -1
- package/src/utils/is-pro-components-supported.ts +11 -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": "4.0.0-
|
|
4
|
+
"version": "4.0.0-beta5",
|
|
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.0-
|
|
44
|
-
"@elementor/editor-canvas": "4.0.0-
|
|
45
|
-
"@elementor/editor-controls": "4.0.0-
|
|
46
|
-
"@elementor/editor-documents": "4.0.0-
|
|
47
|
-
"@elementor/editor-editing-panel": "4.0.0-
|
|
48
|
-
"@elementor/editor-elements": "4.0.0-
|
|
49
|
-
"@elementor/editor-elements-panel": "4.0.0-
|
|
50
|
-
"@elementor/editor-mcp": "4.0.0-
|
|
51
|
-
"@elementor/editor-templates": "4.0.0-
|
|
52
|
-
"@elementor/editor-panels": "4.0.0-
|
|
53
|
-
"@elementor/editor-props": "4.0.0-
|
|
54
|
-
"@elementor/editor-styles-repository": "4.0.0-
|
|
55
|
-
"@elementor/editor-ui": "4.0.0-
|
|
56
|
-
"@elementor/editor-v1-adapters": "4.0.0-
|
|
57
|
-
"@elementor/http-client": "4.0.0-
|
|
43
|
+
"@elementor/editor": "4.0.0-beta5",
|
|
44
|
+
"@elementor/editor-canvas": "4.0.0-beta5",
|
|
45
|
+
"@elementor/editor-controls": "4.0.0-beta5",
|
|
46
|
+
"@elementor/editor-documents": "4.0.0-beta5",
|
|
47
|
+
"@elementor/editor-editing-panel": "4.0.0-beta5",
|
|
48
|
+
"@elementor/editor-elements": "4.0.0-beta5",
|
|
49
|
+
"@elementor/editor-elements-panel": "4.0.0-beta5",
|
|
50
|
+
"@elementor/editor-mcp": "4.0.0-beta5",
|
|
51
|
+
"@elementor/editor-templates": "4.0.0-beta5",
|
|
52
|
+
"@elementor/editor-panels": "4.0.0-beta5",
|
|
53
|
+
"@elementor/editor-props": "4.0.0-beta5",
|
|
54
|
+
"@elementor/editor-styles-repository": "4.0.0-beta5",
|
|
55
|
+
"@elementor/editor-ui": "4.0.0-beta5",
|
|
56
|
+
"@elementor/editor-v1-adapters": "4.0.0-beta5",
|
|
57
|
+
"@elementor/http-client": "4.0.0-beta5",
|
|
58
58
|
"@elementor/icons": "^1.68.0",
|
|
59
|
-
"@elementor/events": "4.0.0-
|
|
60
|
-
"@elementor/query": "4.0.0-
|
|
61
|
-
"@elementor/schema": "4.0.0-
|
|
62
|
-
"@elementor/store": "4.0.0-
|
|
59
|
+
"@elementor/events": "4.0.0-beta5",
|
|
60
|
+
"@elementor/query": "4.0.0-beta5",
|
|
61
|
+
"@elementor/schema": "4.0.0-beta5",
|
|
62
|
+
"@elementor/store": "4.0.0-beta5",
|
|
63
63
|
"@elementor/ui": "1.36.17",
|
|
64
|
-
"@elementor/utils": "4.0.0-
|
|
64
|
+
"@elementor/utils": "4.0.0-beta5",
|
|
65
65
|
"@wordpress/i18n": "^5.13.0",
|
|
66
|
-
"@elementor/editor-notifications": "4.0.0-
|
|
67
|
-
"@elementor/editor-current-user": "4.0.0-
|
|
66
|
+
"@elementor/editor-notifications": "4.0.0-beta5",
|
|
67
|
+
"@elementor/editor-current-user": "4.0.0-beta5"
|
|
68
68
|
},
|
|
69
69
|
"peerDependencies": {
|
|
70
70
|
"react": "^18.3.1",
|
package/src/api.ts
CHANGED
|
@@ -92,14 +92,15 @@ export const apiClient = {
|
|
|
92
92
|
componentId,
|
|
93
93
|
} )
|
|
94
94
|
.then( ( res ) => res.data ),
|
|
95
|
-
getOverridableProps: async (
|
|
95
|
+
getOverridableProps: async ( componentIds: number[] ) =>
|
|
96
96
|
await httpService()
|
|
97
|
-
.get< HttpResponse< OverridableProps
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
97
|
+
.get< HttpResponse< Record< number, OverridableProps | null >, { errors: Record< number, string > } > >(
|
|
98
|
+
`${ BASE_URL }/overridable-props`,
|
|
99
|
+
{
|
|
100
|
+
params: { 'componentIds[]': componentIds },
|
|
101
|
+
}
|
|
102
|
+
)
|
|
103
|
+
.then( ( res ) => res.data ),
|
|
103
104
|
updateArchivedComponents: async ( componentIds: number[], status: DocumentSaveStatus ) =>
|
|
104
105
|
await httpService()
|
|
105
106
|
.post< { data: { failedIds: number[]; successIds: number[]; success: boolean } } >(
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { ComponentsIcon, CrownFilledIcon } from '@elementor/icons';
|
|
3
3
|
import { Box, Button, Divider, Link, List, Stack, Typography } from '@elementor/ui';
|
|
4
|
-
import { hasProInstalled } from '@elementor/utils';
|
|
5
4
|
import { __ } from '@wordpress/i18n';
|
|
6
5
|
|
|
7
6
|
import { useComponents } from '../../hooks/use-components';
|
|
8
7
|
import { useComponentsPermissions } from '../../hooks/use-components-permissions';
|
|
8
|
+
import { isProComponentsSupported, isProOutdatedForComponents } from '../../utils/is-pro-components-supported';
|
|
9
9
|
import { ComponentItem } from './components-item';
|
|
10
10
|
import { LoadingComponents } from './loading-components';
|
|
11
11
|
import { useSearch } from './search-provider';
|
|
12
12
|
|
|
13
13
|
const LEARN_MORE_URL = 'http://go.elementor.com/components-guide-article';
|
|
14
14
|
const UPGRADE_URL = 'https://go.elementor.com/go-pro-components/';
|
|
15
|
+
const UPDATE_PLUGINS_URL = '/wp-admin/plugins.php';
|
|
15
16
|
|
|
16
17
|
// Override legacy panel CSS reset that sets h1-h6 to font-size:100% and font-weight:normal.
|
|
17
18
|
// See: assets/dev/scss/editor/panel/_reset.scss (applied via :where() selector in panel.scss).
|
|
@@ -34,7 +35,11 @@ export function ComponentsList() {
|
|
|
34
35
|
return <EmptySearchResult />;
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
|
|
38
|
+
if ( isProOutdatedForComponents() ) {
|
|
39
|
+
return <ProOutdatedEmptyState />;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return isProComponentsSupported() ? <EmptyState /> : <ProUpgradeEmptyState />;
|
|
38
43
|
}
|
|
39
44
|
|
|
40
45
|
return (
|
|
@@ -83,6 +88,46 @@ const ProUpgradeEmptyState = () => {
|
|
|
83
88
|
);
|
|
84
89
|
};
|
|
85
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
|
+
|
|
86
131
|
const EmptyState = () => {
|
|
87
132
|
const { canCreate } = useComponentsPermissions();
|
|
88
133
|
|
|
@@ -3,7 +3,7 @@ import { __ } from '@wordpress/i18n';
|
|
|
3
3
|
|
|
4
4
|
import { ComponentsUpgradeAlert } from '../components-upgrade-alert';
|
|
5
5
|
|
|
6
|
-
const UPGRADE_URL = 'https://go.elementor.com/go-pro-components-
|
|
6
|
+
export const UPGRADE_URL = 'https://go.elementor.com/go-pro-components-exist-footer/';
|
|
7
7
|
|
|
8
8
|
export function ComponentsProNotification() {
|
|
9
9
|
return (
|
|
@@ -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
|
+
}
|
|
@@ -2,12 +2,13 @@ import * as React from 'react';
|
|
|
2
2
|
import { useLayoutEffect } from 'react';
|
|
3
3
|
import { ThemeProvider } from '@elementor/editor-ui';
|
|
4
4
|
import { Stack } from '@elementor/ui';
|
|
5
|
-
import { hasProInstalled } from '@elementor/utils';
|
|
6
5
|
|
|
7
6
|
import { useComponents } from '../../hooks/use-components';
|
|
7
|
+
import { isProComponentsSupported, isProOutdatedForComponents } from '../../utils/is-pro-components-supported';
|
|
8
8
|
import { ComponentSearch } from './component-search';
|
|
9
9
|
import { ComponentsList } from './components-list';
|
|
10
10
|
import { ComponentsProNotification } from './components-pro-notification';
|
|
11
|
+
import { ComponentsUpdateNotification } from './components-update-notification';
|
|
11
12
|
import { SearchProvider } from './search-provider';
|
|
12
13
|
|
|
13
14
|
const FULL_HEIGHT_STYLE_ID = 'components-full-height-panel';
|
|
@@ -54,8 +55,8 @@ const useFullHeightPanel = () => {
|
|
|
54
55
|
const ComponentsContent = () => {
|
|
55
56
|
const { components, isLoading } = useComponents();
|
|
56
57
|
const hasComponents = ! isLoading && components.length > 0;
|
|
57
|
-
const
|
|
58
|
-
const
|
|
58
|
+
const showProNotification = ! isProComponentsSupported() && hasComponents;
|
|
59
|
+
const isOutdated = isProOutdatedForComponents();
|
|
59
60
|
|
|
60
61
|
useFullHeightPanel();
|
|
61
62
|
|
|
@@ -63,7 +64,7 @@ const ComponentsContent = () => {
|
|
|
63
64
|
<Stack justifyContent="space-between" sx={ { flex: 1, minHeight: 0 } }>
|
|
64
65
|
{ hasComponents && <ComponentSearch /> }
|
|
65
66
|
<ComponentsList />
|
|
66
|
-
{ showProNotification && <ComponentsProNotification /> }
|
|
67
|
+
{ showProNotification && ( isOutdated ? <ComponentsUpdateNotification /> : <ComponentsProNotification /> ) }
|
|
67
68
|
</Stack>
|
|
68
69
|
);
|
|
69
70
|
};
|
|
@@ -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
|
+
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { PencilIcon } from '@elementor/icons';
|
|
3
3
|
import { Box, Stack } from '@elementor/ui';
|
|
4
|
-
import { hasProInstalled } from '@elementor/utils';
|
|
5
4
|
import { __ } from '@wordpress/i18n';
|
|
6
5
|
|
|
7
6
|
import { useComponentsPermissions } from '../../hooks/use-components-permissions';
|
|
8
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';
|
|
9
10
|
import { ComponentsUpgradeAlert } from '../components-upgrade-alert';
|
|
10
11
|
import { DetachAction } from './detach-action';
|
|
11
12
|
import { EmptyState } from './empty-state';
|
|
@@ -13,12 +14,11 @@ import { InstancePanelBody } from './instance-panel-body';
|
|
|
13
14
|
import { EditComponentAction, InstancePanelHeader } from './instance-panel-header';
|
|
14
15
|
import { useInstancePanelData } from './use-instance-panel-data';
|
|
15
16
|
|
|
16
|
-
const EDIT_UPGRADE_URL = 'https://go.elementor.com/go-pro-components-edit/';
|
|
17
|
+
const EDIT_UPGRADE_URL = 'https://go.elementor.com/go-pro-components-Instance-edit-footer/';
|
|
17
18
|
|
|
18
19
|
export function InstanceEditingPanel() {
|
|
19
20
|
const { canEdit } = useComponentsPermissions();
|
|
20
21
|
const data = useInstancePanelData();
|
|
21
|
-
const hasPro = hasProInstalled();
|
|
22
22
|
|
|
23
23
|
if ( ! data ) {
|
|
24
24
|
return null;
|
|
@@ -51,13 +51,22 @@ export function InstanceEditingPanel() {
|
|
|
51
51
|
componentInstanceId={ componentInstanceId }
|
|
52
52
|
/>
|
|
53
53
|
</ComponentInstanceProvider>
|
|
54
|
-
{ !
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|
+
) ) }
|
|
61
70
|
</Box>
|
|
62
71
|
);
|
|
63
72
|
}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
BaseControl,
|
|
11
11
|
controlsRegistry,
|
|
12
12
|
type ControlType,
|
|
13
|
+
ControlTypeContainer,
|
|
13
14
|
createTopLevelObjectType,
|
|
14
15
|
ElementProvider,
|
|
15
16
|
isDynamicPropValue,
|
|
@@ -18,7 +19,7 @@ import {
|
|
|
18
19
|
} from '@elementor/editor-editing-panel';
|
|
19
20
|
import { type Control, getElementSettings, getElementType } from '@elementor/editor-elements';
|
|
20
21
|
import { type AnyTransformable, type PropType, type PropValue } from '@elementor/editor-props';
|
|
21
|
-
import {
|
|
22
|
+
import { Box } from '@elementor/ui';
|
|
22
23
|
|
|
23
24
|
import { useControlsByWidgetType } from '../../hooks/use-controls-by-widget-type';
|
|
24
25
|
import {
|
|
@@ -50,6 +51,7 @@ import { resolveOverridePropValue } from '../../utils/resolve-override-prop-valu
|
|
|
50
51
|
import { ControlLabel } from '../control-label';
|
|
51
52
|
import { OverrideControlInnerElementNotFoundError } from '../errors';
|
|
52
53
|
import { useResolvedOriginValue } from './use-resolved-origin-value';
|
|
54
|
+
import { correctExposedEmptyOverride } from './utils/correct-exposed-empty-override';
|
|
53
55
|
|
|
54
56
|
type Props = {
|
|
55
57
|
overrideKey: string;
|
|
@@ -123,12 +125,14 @@ function OverrideControl( { overridableProp }: InternalProps ) {
|
|
|
123
125
|
return;
|
|
124
126
|
}
|
|
125
127
|
|
|
126
|
-
|
|
128
|
+
let newPropValue = getTempNewValueForDynamicProp(
|
|
127
129
|
propType,
|
|
128
130
|
propValue,
|
|
129
131
|
newValue[ overridableProp.overrideKey ]
|
|
130
132
|
);
|
|
131
133
|
|
|
134
|
+
newPropValue = correctExposedEmptyOverride( newPropValue, matchingOverride );
|
|
135
|
+
|
|
132
136
|
const newOverrideValue = createOverrideValue( {
|
|
133
137
|
matchingOverride,
|
|
134
138
|
overrideKey: overridableProp.overrideKey,
|
|
@@ -214,10 +218,14 @@ function OverrideControl( { overridableProp }: InternalProps ) {
|
|
|
214
218
|
>
|
|
215
219
|
<PropKeyProvider bind={ overridableProp.overrideKey }>
|
|
216
220
|
<ControlReplacementsProvider replacements={ controlReplacements }>
|
|
217
|
-
<
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
+
<Box mb={ 1.5 }>
|
|
222
|
+
<ControlTypeContainer layout={ layout }>
|
|
223
|
+
{ layout !== 'custom' && (
|
|
224
|
+
<ControlLabel>{ overridableProp.label }</ControlLabel>
|
|
225
|
+
) }
|
|
226
|
+
<OriginalControl control={ control } controlProps={ controlProps } />
|
|
227
|
+
</ControlTypeContainer>
|
|
228
|
+
</Box>
|
|
221
229
|
</ControlReplacementsProvider>
|
|
222
230
|
</PropKeyProvider>
|
|
223
231
|
</PropProvider>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type ComponentInstanceOverrideProp } from '../../../prop-types/component-instance-override-prop-type';
|
|
2
|
+
import { type ComponentInstanceOverride } from '../../../prop-types/component-instance-overrides-prop-type';
|
|
3
|
+
import {
|
|
4
|
+
type ComponentOverridableProp,
|
|
5
|
+
componentOverridablePropTypeUtil,
|
|
6
|
+
} from '../../../prop-types/component-overridable-prop-type';
|
|
7
|
+
|
|
8
|
+
type OverrideValue = ComponentInstanceOverrideProp | ComponentOverridableProp;
|
|
9
|
+
|
|
10
|
+
// The control receives the resolved value, so when exposing a prop that was never overridden,
|
|
11
|
+
// origin_value will be the resolved value instead of null.
|
|
12
|
+
// So here, we correct this by resetting origin_value to null.
|
|
13
|
+
export function correctExposedEmptyOverride(
|
|
14
|
+
newPropValue: OverrideValue,
|
|
15
|
+
matchingOverride: ComponentInstanceOverride | null
|
|
16
|
+
): OverrideValue {
|
|
17
|
+
const newOverridableValue = componentOverridablePropTypeUtil.extract( newPropValue );
|
|
18
|
+
const isExposingEmptyOverride = newOverridableValue && matchingOverride === null;
|
|
19
|
+
|
|
20
|
+
if ( ! isExposingEmptyOverride ) {
|
|
21
|
+
return newPropValue;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return componentOverridablePropTypeUtil.create( {
|
|
25
|
+
override_key: newOverridableValue.override_key,
|
|
26
|
+
origin_value: null,
|
|
27
|
+
} );
|
|
28
|
+
}
|
|
@@ -25,6 +25,7 @@ import { type ComponentsSlice, selectComponentByUid } from './store/store';
|
|
|
25
25
|
import { type ComponentRenderContext, type ExtendedWindow } from './types';
|
|
26
26
|
import { detachComponentInstance } from './utils/detach-component-instance';
|
|
27
27
|
import { formatComponentElementsId } from './utils/format-component-elements-id';
|
|
28
|
+
import { isProComponentsSupported, isProOutdatedForComponents } from './utils/is-pro-components-supported';
|
|
28
29
|
import { switchToComponent } from './utils/switch-to-component';
|
|
29
30
|
import { trackComponentEvent } from './utils/tracking';
|
|
30
31
|
|
|
@@ -53,21 +54,30 @@ type ComponentModelInstance = BackboneModel< ComponentModel > & {
|
|
|
53
54
|
|
|
54
55
|
export const COMPONENT_WIDGET_TYPE = 'e-component';
|
|
55
56
|
|
|
56
|
-
const
|
|
57
|
+
const EDIT_COMPONENT_DB_CLICK_UPGRADE_URL =
|
|
58
|
+
'https://go.elementor.com/go-pro-components-Instance-edit-canvas-double-click/';
|
|
59
|
+
const EDIT_COMPONENT_CONTEXT_MENU_UPGRADE_URL =
|
|
60
|
+
'https://go.elementor.com/go-pro-components-Instance-edit-context-menu/';
|
|
61
|
+
|
|
62
|
+
const UPDATE_PLUGINS_URL = '/wp-admin/plugins.php';
|
|
57
63
|
|
|
58
64
|
const COMPONENT_EDIT_UPGRADE_NOTIFICATION_ID = 'component-edit-upgrade';
|
|
65
|
+
const COMPONENT_EDIT_UPDATE_NOTIFICATION_ID = 'component-edit-update';
|
|
66
|
+
|
|
67
|
+
const COMPONENT_EDIT_UPGRADE_AUTO_HIDE_DURATION = 2000;
|
|
59
68
|
|
|
60
69
|
function notifyComponentEditUpgrade() {
|
|
61
70
|
notify( {
|
|
62
71
|
type: 'promotion',
|
|
63
72
|
id: COMPONENT_EDIT_UPGRADE_NOTIFICATION_ID,
|
|
64
73
|
message: __( 'Editing components requires an active Pro subscription.', 'elementor' ),
|
|
74
|
+
autoHideDuration: COMPONENT_EDIT_UPGRADE_AUTO_HIDE_DURATION,
|
|
65
75
|
additionalActionProps: [
|
|
66
76
|
{
|
|
67
77
|
size: 'small',
|
|
68
78
|
variant: 'contained',
|
|
69
79
|
color: 'promotion',
|
|
70
|
-
href:
|
|
80
|
+
href: EDIT_COMPONENT_DB_CLICK_UPGRADE_URL,
|
|
71
81
|
target: '_blank',
|
|
72
82
|
children: __( 'Upgrade Now', 'elementor' ),
|
|
73
83
|
},
|
|
@@ -75,6 +85,24 @@ function notifyComponentEditUpgrade() {
|
|
|
75
85
|
} );
|
|
76
86
|
}
|
|
77
87
|
|
|
88
|
+
function notifyComponentEditUpdate() {
|
|
89
|
+
notify( {
|
|
90
|
+
type: 'info',
|
|
91
|
+
id: COMPONENT_EDIT_UPDATE_NOTIFICATION_ID,
|
|
92
|
+
message: __( 'To edit components, update Elementor Pro to the latest version.', 'elementor' ),
|
|
93
|
+
additionalActionProps: [
|
|
94
|
+
{
|
|
95
|
+
size: 'small',
|
|
96
|
+
variant: 'contained',
|
|
97
|
+
color: 'info',
|
|
98
|
+
href: UPDATE_PLUGINS_URL,
|
|
99
|
+
target: '_blank',
|
|
100
|
+
children: __( 'Update Now', 'elementor' ),
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
} );
|
|
104
|
+
}
|
|
105
|
+
|
|
78
106
|
const updateGroups = ( groups: ContextMenuGroup[], config: ContextMenuGroupConfig ): ContextMenuGroup[] => {
|
|
79
107
|
const disableMap = new Map( Object.entries( config.disable ?? {} ) );
|
|
80
108
|
const addMap = new Map( Object.entries( config.add ?? {} ) );
|
|
@@ -235,16 +263,18 @@ function createComponentView( options: ComponentTypeOptions ): typeof ElementVie
|
|
|
235
263
|
_getContextMenuConfig() {
|
|
236
264
|
const isAdministrator = isUserAdministrator();
|
|
237
265
|
const hasPro = hasProInstalled();
|
|
266
|
+
const isOutdated = isProOutdatedForComponents();
|
|
267
|
+
const showPromoBadge = ! hasPro && ! isOutdated;
|
|
238
268
|
|
|
239
269
|
const badgeClass = 'elementor-context-menu-list__item__shortcut__promotion-badge';
|
|
240
|
-
const proBadge = `<a href="${
|
|
270
|
+
const proBadge = `<a href="${ EDIT_COMPONENT_CONTEXT_MENU_UPGRADE_URL }" target="_blank" onclick="event.stopPropagation()" class="${ badgeClass }"><i class="eicon-upgrade-crown"></i></a>`;
|
|
241
271
|
|
|
242
272
|
const editComponentAction: ContextMenuAction = {
|
|
243
273
|
name: 'edit component',
|
|
244
274
|
icon: 'eicon-edit',
|
|
245
275
|
title: () => __( 'Edit Component', 'elementor' ),
|
|
246
|
-
...(
|
|
247
|
-
isEnabled: () =>
|
|
276
|
+
...( showPromoBadge && { shortcut: proBadge, hasShortcutAction: true } ),
|
|
277
|
+
isEnabled: () => isProComponentsSupported() || isOutdated,
|
|
248
278
|
callback: ( _: unknown, eventData: ContextMenuEventData ) => this.editComponent( eventData ),
|
|
249
279
|
};
|
|
250
280
|
|
|
@@ -286,9 +316,12 @@ function createComponentView( options: ComponentTypeOptions ): typeof ElementVie
|
|
|
286
316
|
}
|
|
287
317
|
|
|
288
318
|
editComponent( { trigger, location, secondaryLocation }: ContextMenuEventData ) {
|
|
289
|
-
|
|
319
|
+
if ( isProOutdatedForComponents() ) {
|
|
320
|
+
notifyComponentEditUpdate();
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
290
323
|
|
|
291
|
-
if ( !
|
|
324
|
+
if ( ! isProComponentsSupported() || this.isComponentCurrentlyEdited() ) {
|
|
292
325
|
return;
|
|
293
326
|
}
|
|
294
327
|
|
|
@@ -341,6 +374,11 @@ function createComponentView( options: ComponentTypeOptions ): typeof ElementVie
|
|
|
341
374
|
return;
|
|
342
375
|
}
|
|
343
376
|
|
|
377
|
+
if ( isProOutdatedForComponents() ) {
|
|
378
|
+
notifyComponentEditUpdate();
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
|
|
344
382
|
if ( ! hasProInstalled() ) {
|
|
345
383
|
notifyComponentEditUpgrade();
|
|
346
384
|
return;
|
|
@@ -3,31 +3,14 @@ import { __dispatch as dispatch, __getState as getState } from '@elementor/store
|
|
|
3
3
|
import { apiClient } from '../../api';
|
|
4
4
|
import { selectIsOverridablePropsLoaded, slice } from '../store';
|
|
5
5
|
|
|
6
|
-
export function loadComponentsOverridableProps( componentIds: number[] ) {
|
|
7
|
-
|
|
8
|
-
return;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
return Promise.all( componentIds.map( loadComponentOverrides ) );
|
|
12
|
-
}
|
|
6
|
+
export async function loadComponentsOverridableProps( componentIds: number[] ) {
|
|
7
|
+
const unloadedIds = componentIds.filter( ( id ) => ! selectIsOverridablePropsLoaded( getState(), id ) );
|
|
13
8
|
|
|
14
|
-
|
|
15
|
-
const isOverridablePropsLoaded = selectIsOverridablePropsLoaded( getState(), componentId );
|
|
16
|
-
|
|
17
|
-
if ( isOverridablePropsLoaded ) {
|
|
9
|
+
if ( ! unloadedIds.length ) {
|
|
18
10
|
return;
|
|
19
11
|
}
|
|
20
12
|
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
if ( ! overridableProps ) {
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
13
|
+
const { data } = await apiClient.getOverridableProps( unloadedIds );
|
|
26
14
|
|
|
27
|
-
dispatch(
|
|
28
|
-
slice.actions.setOverridableProps( {
|
|
29
|
-
componentId,
|
|
30
|
-
overridableProps,
|
|
31
|
-
} )
|
|
32
|
-
);
|
|
15
|
+
dispatch( slice.actions.loadOverridableProps( data ) );
|
|
33
16
|
}
|
|
@@ -105,6 +105,25 @@ const baseSlice = createSlice( {
|
|
|
105
105
|
|
|
106
106
|
component.overridableProps = payload.overridableProps;
|
|
107
107
|
},
|
|
108
|
+
loadOverridableProps: (
|
|
109
|
+
state,
|
|
110
|
+
{ payload }: PayloadAction< Record< ComponentId, OverridableProps | null > >
|
|
111
|
+
) => {
|
|
112
|
+
const componentIds = Object.keys( payload );
|
|
113
|
+
|
|
114
|
+
componentIds.forEach( ( id ) => {
|
|
115
|
+
const componentId = Number( id );
|
|
116
|
+
const overridableProps = payload[ componentId ];
|
|
117
|
+
|
|
118
|
+
const component = state.data.find( ( comp ) => comp.id === componentId );
|
|
119
|
+
|
|
120
|
+
if ( ! component || ! overridableProps ) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
component.overridableProps = overridableProps;
|
|
125
|
+
} );
|
|
126
|
+
},
|
|
108
127
|
rename: ( state, { payload }: PayloadAction< { componentUid: string; name: string } > ) => {
|
|
109
128
|
const component = state.data.find( ( comp ) => comp.uid === payload.componentUid );
|
|
110
129
|
|
|
@@ -9,7 +9,7 @@ import { type DocumentSaveStatus } from '../types';
|
|
|
9
9
|
import { getComponentDocuments } from '../utils/get-component-documents';
|
|
10
10
|
|
|
11
11
|
const INSUFFICIENT_PERMISSIONS_ERROR_CODE = 'insufficient_permissions';
|
|
12
|
-
const PUBLISH_UPGRADE_URL = 'https://go.elementor.com/go-pro-components-
|
|
12
|
+
const PUBLISH_UPGRADE_URL = 'https://go.elementor.com/go-pro-components-Instance-draft-failure/';
|
|
13
13
|
const PUBLISH_UPGRADE_NOTIFICATION_ID = 'component-publish-upgrade';
|
|
14
14
|
|
|
15
15
|
type Options = {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { hasProInstalled, isProAtLeast } from '@elementor/utils';
|
|
2
|
+
|
|
3
|
+
const MIN_PRO_VERSION_FOR_COMPONENTS = '4.0';
|
|
4
|
+
|
|
5
|
+
export function isProComponentsSupported(): boolean {
|
|
6
|
+
return hasProInstalled() && isProAtLeast( MIN_PRO_VERSION_FOR_COMPONENTS );
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function isProOutdatedForComponents(): boolean {
|
|
10
|
+
return hasProInstalled() && ! isProAtLeast( MIN_PRO_VERSION_FOR_COMPONENTS );
|
|
11
|
+
}
|