@elementor/editor-components 4.0.0-672 → 4.0.0-674

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/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-672",
4
+ "version": "4.0.0-674",
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-672",
44
- "@elementor/editor-canvas": "4.0.0-672",
45
- "@elementor/editor-controls": "4.0.0-672",
46
- "@elementor/editor-documents": "4.0.0-672",
47
- "@elementor/editor-editing-panel": "4.0.0-672",
48
- "@elementor/editor-elements": "4.0.0-672",
49
- "@elementor/editor-elements-panel": "4.0.0-672",
50
- "@elementor/editor-mcp": "4.0.0-672",
51
- "@elementor/editor-templates": "4.0.0-672",
52
- "@elementor/editor-panels": "4.0.0-672",
53
- "@elementor/editor-props": "4.0.0-672",
54
- "@elementor/editor-styles-repository": "4.0.0-672",
55
- "@elementor/editor-ui": "4.0.0-672",
56
- "@elementor/editor-v1-adapters": "4.0.0-672",
57
- "@elementor/http-client": "4.0.0-672",
43
+ "@elementor/editor": "4.0.0-674",
44
+ "@elementor/editor-canvas": "4.0.0-674",
45
+ "@elementor/editor-controls": "4.0.0-674",
46
+ "@elementor/editor-documents": "4.0.0-674",
47
+ "@elementor/editor-editing-panel": "4.0.0-674",
48
+ "@elementor/editor-elements": "4.0.0-674",
49
+ "@elementor/editor-elements-panel": "4.0.0-674",
50
+ "@elementor/editor-mcp": "4.0.0-674",
51
+ "@elementor/editor-templates": "4.0.0-674",
52
+ "@elementor/editor-panels": "4.0.0-674",
53
+ "@elementor/editor-props": "4.0.0-674",
54
+ "@elementor/editor-styles-repository": "4.0.0-674",
55
+ "@elementor/editor-ui": "4.0.0-674",
56
+ "@elementor/editor-v1-adapters": "4.0.0-674",
57
+ "@elementor/http-client": "4.0.0-674",
58
58
  "@elementor/icons": "^1.68.0",
59
- "@elementor/events": "4.0.0-672",
60
- "@elementor/query": "4.0.0-672",
61
- "@elementor/schema": "4.0.0-672",
62
- "@elementor/store": "4.0.0-672",
59
+ "@elementor/events": "4.0.0-674",
60
+ "@elementor/query": "4.0.0-674",
61
+ "@elementor/schema": "4.0.0-674",
62
+ "@elementor/store": "4.0.0-674",
63
63
  "@elementor/ui": "1.36.17",
64
- "@elementor/utils": "4.0.0-672",
64
+ "@elementor/utils": "4.0.0-674",
65
65
  "@wordpress/i18n": "^5.13.0",
66
- "@elementor/editor-notifications": "4.0.0-672",
67
- "@elementor/editor-current-user": "4.0.0-672"
66
+ "@elementor/editor-notifications": "4.0.0-674",
67
+ "@elementor/editor-current-user": "4.0.0-674"
68
68
  },
69
69
  "peerDependencies": {
70
70
  "react": "^18.3.1",
@@ -1,6 +1,7 @@
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
+ import { hasProInstalled } from '@elementor/utils';
4
5
  import { __ } from '@wordpress/i18n';
5
6
 
6
7
  import { useComponents } from '../../hooks/use-components';
@@ -10,6 +11,7 @@ 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/';
13
15
 
14
16
  // Override legacy panel CSS reset that sets h1-h6 to font-size:100% and font-weight:normal.
15
17
  // See: assets/dev/scss/editor/panel/_reset.scss (applied via :where() selector in panel.scss).
@@ -28,7 +30,11 @@ export function ComponentsList() {
28
30
  const isEmpty = ! components?.length;
29
31
 
30
32
  if ( isEmpty ) {
31
- return searchValue.length ? <EmptySearchResult /> : <EmptyState />;
33
+ if ( searchValue.length ) {
34
+ return <EmptySearchResult />;
35
+ }
36
+
37
+ return hasProInstalled() ? <EmptyState /> : <ProUpgradeEmptyState />;
32
38
  }
33
39
 
34
40
  return (
@@ -40,7 +46,44 @@ export function ComponentsList() {
40
46
  );
41
47
  }
42
48
 
43
- export const EmptyState = () => {
49
+ const ProUpgradeEmptyState = () => {
50
+ return (
51
+ <Stack
52
+ alignItems="center"
53
+ justifyContent="start"
54
+ height="100%"
55
+ sx={ { px: 2, py: 4 } }
56
+ gap={ 2 }
57
+ overflow="hidden"
58
+ >
59
+ <Stack alignItems="center" gap={ 1 }>
60
+ <ComponentsIcon fontSize="large" sx={ { color: 'text.secondary' } } />
61
+
62
+ <Typography align="center" variant="subtitle2" color="text.secondary" sx={ SUBTITLE_OVERRIDE_SX }>
63
+ { __( 'Create Reusable Components', 'elementor' ) }
64
+ </Typography>
65
+
66
+ <Typography align="center" variant="caption" color="secondary" sx={ { maxWidth: 200 } }>
67
+ { __( 'Create design elements that sync across your entire site.', 'elementor' ) }
68
+ </Typography>
69
+ </Stack>
70
+
71
+ <Button
72
+ variant="contained"
73
+ color="promotion"
74
+ size="small"
75
+ startIcon={ <CrownFilledIcon /> }
76
+ href={ UPGRADE_URL }
77
+ target="_blank"
78
+ rel="noopener noreferrer"
79
+ >
80
+ { __( 'Upgrade now', 'elementor' ) }
81
+ </Button>
82
+ </Stack>
83
+ );
84
+ };
85
+
86
+ const EmptyState = () => {
44
87
  const { canCreate } = useComponentsPermissions();
45
88
 
46
89
  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
+ const UPGRADE_URL = 'https://go.elementor.com/go-pro-components-create/';
7
+
6
8
  export function ComponentsProNotification() {
7
9
  return (
8
- <Box sx={ { px: 2 } }>
9
- <InfoAlert>
10
- <Typography variant="caption" component="span">
11
- <Typography variant="caption" component="span" fontWeight="bold">
12
- { __( 'Try Components for free:', 'elementor' ) }
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
  }
@@ -1,5 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { ThemeProvider } from '@elementor/editor-ui';
3
+ import { Stack } from '@elementor/ui';
4
+ import { hasProInstalled } from '@elementor/utils';
3
5
 
4
6
  import { useComponents } from '../../hooks/use-components';
5
7
  import { ComponentSearch } from './component-search';
@@ -10,13 +12,15 @@ import { SearchProvider } from './search-provider';
10
12
  const ComponentsContent = () => {
11
13
  const { components, isLoading } = useComponents();
12
14
  const hasComponents = ! isLoading && components.length > 0;
15
+ const hasPro = hasProInstalled();
16
+ const showProNotification = ! hasPro && hasComponents;
13
17
 
14
18
  return (
15
- <>
19
+ <Stack sx={ { height: '100%' } }>
16
20
  { hasComponents && <ComponentSearch /> }
17
- { hasComponents && <ComponentsProNotification /> }
18
21
  <ComponentsList />
19
- </>
22
+ { showProNotification && <ComponentsProNotification /> }
23
+ </Stack>
20
24
  );
21
25
  };
22
26
 
@@ -1,41 +1,53 @@
1
1
  import * as React from 'react';
2
- import { Box, ListItemButton, Skeleton, Stack } from '@elementor/ui';
2
+ import { Box, Skeleton, Stack } from '@elementor/ui';
3
3
 
4
- const ROWS = Array.from( { length: 6 }, ( _, index ) => index );
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
- top: 0,
21
+ bottom: 0,
19
22
  content: '""',
20
23
  left: 0,
21
24
  width: '100%',
22
- height: '300px',
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
- <ListItemButton
32
+ <Box
30
33
  key={ row }
31
- sx={ { border: 'solid 1px', borderColor: 'divider', py: 0.5, px: 1 } }
32
- shape="rounded"
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
- <Box display="flex" gap={ 1 } width="100%">
35
- <Skeleton variant="text" width={ '24px' } height={ '36px' } />
36
- <Skeleton variant="text" width={ '100%' } height={ '36px' } />
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,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' } }>
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
+ }
@@ -1,19 +1,24 @@
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';
4
5
  import { __ } from '@wordpress/i18n';
5
6
 
6
7
  import { useComponentsPermissions } from '../../hooks/use-components-permissions';
7
8
  import { ComponentInstanceProvider } from '../../provider/component-instance-context';
9
+ import { ComponentsUpgradeAlert } from '../components-upgrade-alert';
8
10
  import { DetachAction } from './detach-action';
9
11
  import { EmptyState } from './empty-state';
10
12
  import { InstancePanelBody } from './instance-panel-body';
11
13
  import { EditComponentAction, InstancePanelHeader } from './instance-panel-header';
12
14
  import { useInstancePanelData } from './use-instance-panel-data';
13
15
 
16
+ const EDIT_UPGRADE_URL = 'https://go.elementor.com/go-pro-components-edit/';
17
+
14
18
  export function InstanceEditingPanel() {
15
19
  const { canEdit } = useComponentsPermissions();
16
20
  const data = useInstancePanelData();
21
+ const hasPro = hasProInstalled();
17
22
 
18
23
  if ( ! data ) {
19
24
  return null;
@@ -32,7 +37,7 @@ export function InstanceEditingPanel() {
32
37
  );
33
38
 
34
39
  return (
35
- <Box data-testid="instance-editing-panel">
40
+ <Box data-testid="instance-editing-panel" sx={ { display: 'flex', flexDirection: 'column', height: '100%' } }>
36
41
  <ComponentInstanceProvider
37
42
  componentId={ componentId }
38
43
  overrides={ overrides }
@@ -46,6 +51,13 @@ export function InstanceEditingPanel() {
46
51
  componentInstanceId={ componentInstanceId }
47
52
  />
48
53
  </ComponentInstanceProvider>
54
+ { ! hasPro && (
55
+ <ComponentsUpgradeAlert
56
+ title={ __( 'Edit components', 'elementor' ) }
57
+ description={ __( 'Editing components requires an active Pro subscription.', 'elementor' ) }
58
+ upgradeUrl={ EDIT_UPGRADE_URL }
59
+ />
60
+ ) }
49
61
  </Box>
50
62
  );
51
63
  }
@@ -61,7 +61,7 @@ function notifyComponentEditUpgrade() {
61
61
  notify( {
62
62
  type: 'promotion',
63
63
  id: COMPONENT_EDIT_UPGRADE_NOTIFICATION_ID,
64
- message: __( 'Your Pro subscription has expired. Renew to edit components.', 'elementor' ),
64
+ message: __( 'Editing components requires an active Pro subscription.', 'elementor' ),
65
65
  additionalActionProps: [
66
66
  {
67
67
  size: 'small',
@@ -236,9 +236,8 @@ function createComponentView( options: ComponentTypeOptions ): typeof ElementVie
236
236
  const isAdministrator = isUserAdministrator();
237
237
  const hasPro = hasProInstalled();
238
238
 
239
- const proLabel = __( 'PRO', 'elementor' );
240
- const badgeClass = 'elementor-context-menu-list__item__shortcut__new-badge';
241
- const proBadge = `<a href="${ EDIT_COMPONENT_UPGRADE_URL }" target="_blank" onclick="event.stopPropagation()" class="${ badgeClass }">${ proLabel }</a>`;
239
+ const badgeClass = 'elementor-context-menu-list__item__shortcut__promotion-badge';
240
+ const proBadge = `<a href="${ EDIT_COMPONENT_UPGRADE_URL }" target="_blank" onclick="event.stopPropagation()" class="${ badgeClass }"><i class="eicon-upgrade-crown"></i></a>`;
242
241
 
243
242
  const editComponentAction: ContextMenuAction = {
244
243
  name: 'edit component',
package/src/index.ts CHANGED
@@ -5,12 +5,7 @@ export { apiClient } from './api';
5
5
  export { ComponentSearch } from './components/components-tab/component-search';
6
6
  export { ComponentItem, ComponentName } from './components/components-tab/components-item';
7
7
  export type { ComponentItemProps } from './components/components-tab/components-item';
8
- export {
9
- ComponentsList,
10
- EmptySearchResult,
11
- EmptyState as ComponentsEmptyState,
12
- useFilteredComponents,
13
- } from './components/components-tab/components-list';
8
+ export { ComponentsList, EmptySearchResult, useFilteredComponents } from './components/components-tab/components-list';
14
9
  export { LoadingComponents } from './components/components-tab/loading-components';
15
10
  export { SearchProvider } from './components/components-tab/search-provider';
16
11
  export { EmptyState as InstanceEmptyState } from './components/instance-editing-panel/empty-state';