@elementor/editor-components 3.35.0-341 → 3.35.0-343

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": "3.35.0-341",
4
+ "version": "3.35.0-343",
5
5
  "private": false,
6
6
  "author": "Elementor Team",
7
7
  "homepage": "https://elementor.com/",
@@ -40,28 +40,29 @@
40
40
  "dev": "tsup --config=../../tsup.dev.ts"
41
41
  },
42
42
  "dependencies": {
43
- "@elementor/editor": "3.35.0-341",
44
- "@elementor/editor-canvas": "3.35.0-341",
45
- "@elementor/editor-controls": "3.35.0-341",
46
- "@elementor/editor-documents": "3.35.0-341",
47
- "@elementor/editor-editing-panel": "3.35.0-341",
48
- "@elementor/editor-elements": "3.35.0-341",
49
- "@elementor/editor-elements-panel": "3.35.0-341",
50
- "@elementor/editor-mcp": "3.35.0-341",
51
- "@elementor/editor-props": "3.35.0-341",
52
- "@elementor/editor-styles-repository": "3.35.0-341",
53
- "@elementor/editor-ui": "3.35.0-341",
54
- "@elementor/editor-v1-adapters": "3.35.0-341",
55
- "@elementor/http-client": "3.35.0-341",
43
+ "@elementor/editor": "3.35.0-343",
44
+ "@elementor/editor-canvas": "3.35.0-343",
45
+ "@elementor/editor-controls": "3.35.0-343",
46
+ "@elementor/editor-documents": "3.35.0-343",
47
+ "@elementor/editor-editing-panel": "3.35.0-343",
48
+ "@elementor/editor-elements": "3.35.0-343",
49
+ "@elementor/editor-elements-panel": "3.35.0-343",
50
+ "@elementor/editor-mcp": "3.35.0-343",
51
+ "@elementor/editor-panels": "3.35.0-343",
52
+ "@elementor/editor-props": "3.35.0-343",
53
+ "@elementor/editor-styles-repository": "3.35.0-343",
54
+ "@elementor/editor-ui": "3.35.0-343",
55
+ "@elementor/editor-v1-adapters": "3.35.0-343",
56
+ "@elementor/http-client": "3.35.0-343",
56
57
  "@elementor/icons": "^1.62.0",
57
- "@elementor/mixpanel": "3.35.0-341",
58
- "@elementor/query": "3.35.0-341",
59
- "@elementor/schema": "3.35.0-341",
60
- "@elementor/store": "3.35.0-341",
58
+ "@elementor/mixpanel": "3.35.0-343",
59
+ "@elementor/query": "3.35.0-343",
60
+ "@elementor/schema": "3.35.0-343",
61
+ "@elementor/store": "3.35.0-343",
61
62
  "@elementor/ui": "1.36.17",
62
- "@elementor/utils": "3.35.0-341",
63
+ "@elementor/utils": "3.35.0-343",
63
64
  "@wordpress/i18n": "^5.13.0",
64
- "@elementor/editor-notifications": "3.35.0-341"
65
+ "@elementor/editor-notifications": "3.35.0-343"
65
66
  },
66
67
  "peerDependencies": {
67
68
  "react": "^18.3.1",
@@ -0,0 +1,35 @@
1
+ import * as React from 'react';
2
+ import { ComponentPropListIcon, PencilIcon } from '@elementor/icons';
3
+ import { Button, Stack, Typography } from '@elementor/ui';
4
+ import { __ } from '@wordpress/i18n';
5
+
6
+ export const EmptyState = ( { onEditComponent }: { onEditComponent: () => void } ) => {
7
+ return (
8
+ <Stack
9
+ alignItems="center"
10
+ justifyContent="start"
11
+ height="100%"
12
+ color="text.secondary"
13
+ sx={ { p: 2.5, pt: 8, pb: 5.5, mt: 1 } }
14
+ gap={ 1.5 }
15
+ >
16
+ <ComponentPropListIcon fontSize="large" />
17
+
18
+ <Typography align="center" variant="subtitle2">
19
+ { __( 'No properties yet', 'elementor' ) }
20
+ </Typography>
21
+
22
+ <Typography align="center" variant="caption" maxWidth="170px">
23
+ { __(
24
+ 'Edit the component to add properties, manage them or update the design across all instances.',
25
+ 'elementor'
26
+ ) }
27
+ </Typography>
28
+
29
+ <Button variant="outlined" color="secondary" size="small" sx={ { mt: 1 } } onClick={ onEditComponent }>
30
+ <PencilIcon fontSize="small" />
31
+ { __( 'Edit component', 'elementor' ) }
32
+ </Button>
33
+ </Stack>
34
+ );
35
+ };
@@ -0,0 +1,73 @@
1
+ import * as React from 'react';
2
+ import { useElement } from '@elementor/editor-editing-panel';
3
+ import { useElementSetting, useSelectedElement } from '@elementor/editor-elements';
4
+ import { PanelBody, PanelHeader, PanelHeaderTitle } from '@elementor/editor-panels';
5
+ import { type NumberPropValue } from '@elementor/editor-props';
6
+ import { ComponentsIcon, PencilIcon } from '@elementor/icons';
7
+ import { __getState as getState } from '@elementor/store';
8
+ import { IconButton, Stack, Tooltip } from '@elementor/ui';
9
+ import { __ } from '@wordpress/i18n';
10
+
11
+ import { componentInstancePropTypeUtil } from '../../prop-types/component-instance-prop-type';
12
+ import { selectComponent, selectOverridableProps } from '../../store/store';
13
+ import { type OverridablePropsGroup } from '../../types';
14
+ import { switchToComponent } from '../../utils/switch-to-component';
15
+ import { EmptyState } from './empty-state';
16
+ import { OverridePropsGroup } from './override-props-group';
17
+
18
+ export function InstanceEditingPanel() {
19
+ const { element } = useElement();
20
+ const settings = useElementSetting( element.id, 'component_instance' );
21
+ const componentId = ( componentInstancePropTypeUtil.extract( settings )?.component_id as NumberPropValue ).value;
22
+
23
+ const component = componentId ? selectComponent( getState(), componentId ) : null;
24
+ const overridableProps = componentId ? selectOverridableProps( getState(), componentId ) : null;
25
+
26
+ const componentInstanceId = useSelectedElement()?.element?.id ?? null;
27
+
28
+ if ( ! componentId || ! overridableProps || ! component ) {
29
+ return null;
30
+ }
31
+
32
+ /* translators: %s: component name. */
33
+ const panelTitle = __( 'Edit %s', 'elementor' ).replace( '%s', component.name );
34
+
35
+ const handleEditComponent = () => switchToComponent( componentId, componentInstanceId );
36
+
37
+ const groups = overridableProps.groups.order
38
+ .map( ( groupId ) =>
39
+ overridableProps.groups.items[ groupId ] ? overridableProps.groups.items[ groupId ] : null
40
+ )
41
+ .filter( Boolean ) as OverridablePropsGroup[];
42
+
43
+ const isEmpty = groups.length === 0 || Object.keys( overridableProps.props ).length === 0;
44
+
45
+ return (
46
+ <>
47
+ <PanelHeader sx={ { justifyContent: 'start' } }>
48
+ <Stack direction="row" alignContent="space-between" flexGrow={ 1 }>
49
+ <Stack direction="row" alignItems="center" justifyContent="start" gap={ 1 } flexGrow={ 1 }>
50
+ <ComponentsIcon fontSize="small" sx={ { color: 'text.tertiary' } } />
51
+ <PanelHeaderTitle>{ component.name }</PanelHeaderTitle>
52
+ </Stack>
53
+ <Tooltip title={ panelTitle }>
54
+ <IconButton size="tiny" onClick={ handleEditComponent } aria-label={ panelTitle }>
55
+ <PencilIcon fontSize="tiny" />
56
+ </IconButton>
57
+ </Tooltip>
58
+ </Stack>
59
+ </PanelHeader>
60
+ <PanelBody>
61
+ { isEmpty ? (
62
+ <EmptyState onEditComponent={ handleEditComponent } />
63
+ ) : (
64
+ <Stack direction="column" alignItems="stretch">
65
+ { groups.map( ( group ) => (
66
+ <OverridePropsGroup key={ group.id } group={ group } props={ overridableProps.props } />
67
+ ) ) }
68
+ </Stack>
69
+ ) }
70
+ </PanelBody>
71
+ </>
72
+ );
73
+ }
@@ -0,0 +1,56 @@
1
+ import * as React from 'react';
2
+ import { useId } from 'react';
3
+ import { useStateByElement } from '@elementor/editor-editing-panel';
4
+ import { CollapseIcon } from '@elementor/editor-ui';
5
+ import { Collapse, ListItemButton, ListItemText, Stack } from '@elementor/ui';
6
+
7
+ import { type OverridableProp, type OverridablePropsGroup } from '../../types';
8
+
9
+ type Props = {
10
+ group: OverridablePropsGroup;
11
+ props: Record< string, OverridableProp >;
12
+ };
13
+
14
+ export function OverridePropsGroup( { group, props }: Props ) {
15
+ const [ isOpen, setIsOpen ] = useStateByElement( group.id, true );
16
+
17
+ const handleClick = () => {
18
+ setIsOpen( ! isOpen );
19
+ };
20
+
21
+ const id = useId();
22
+ const labelId = `label-${ id }`;
23
+ const contentId = `content-${ id }`;
24
+
25
+ const title = group.label;
26
+
27
+ return (
28
+ <>
29
+ <ListItemButton
30
+ id={ labelId }
31
+ aria-controls={ contentId }
32
+ aria-label={ `${ title } section` }
33
+ onClick={ handleClick }
34
+ p={ 0 }
35
+ sx={ { '&:hover': { backgroundColor: 'transparent' } } }
36
+ >
37
+ <Stack direction="row" alignItems="center" justifyItems="start" flexGrow={ 1 } gap={ 0.5 }>
38
+ <ListItemText
39
+ secondary={ title }
40
+ secondaryTypographyProps={ { color: 'text.primary', variant: 'caption', fontWeight: 'bold' } }
41
+ sx={ { flexGrow: 0, flexShrink: 1, marginInlineEnd: 1 } }
42
+ />
43
+ </Stack>
44
+ <CollapseIcon open={ isOpen } color="secondary" fontSize="tiny" />
45
+ </ListItemButton>
46
+ <Collapse id={ contentId } aria-labelledby={ labelId } in={ isOpen } timeout="auto">
47
+ <Stack direction="column" gap={ 1 } p={ 2 }>
48
+ { group.props.map( ( propId ) => (
49
+ // TODO: Render actual controls
50
+ <pre key={ propId }>{ JSON.stringify( props[ propId ], null, 2 ) }</pre>
51
+ ) ) }
52
+ </Stack>
53
+ </Collapse>
54
+ </>
55
+ );
56
+ }
@@ -8,11 +8,11 @@ import {
8
8
  type LegacyWindow,
9
9
  } from '@elementor/editor-canvas';
10
10
  import { getCurrentDocument } from '@elementor/editor-documents';
11
- import { __privateRunCommand as runCommand } from '@elementor/editor-v1-adapters';
12
11
  import { __ } from '@wordpress/i18n';
13
12
 
14
13
  import { apiClient } from './api';
15
14
  import { type ComponentInstancePropValue, type ExtendedWindow } from './types';
15
+ import { switchToComponent } from './utils/switch-to-component';
16
16
  import { trackComponentEvent } from './utils/tracking';
17
17
 
18
18
  type ContextMenuEventData = { location: string; secondaryLocation: string; trigger: string };
@@ -179,12 +179,7 @@ function createComponentView(
179
179
  if ( ! isAllowedToSwitchDocument ) {
180
180
  options.showLockedByModal?.( lockedBy || '' );
181
181
  } else {
182
- runCommand( 'editor/documents/switch', {
183
- id: this.getComponentId(),
184
- mode: 'autosave',
185
- selector: `[data-id="${ this.model.get( 'id' ) }"]`,
186
- shouldScroll: false,
187
- } );
182
+ switchToComponent( this.getComponentId(), this.model.get( 'id' ) );
188
183
  }
189
184
  }
190
185
 
@@ -0,0 +1,15 @@
1
+ import { useElement } from '@elementor/editor-editing-panel';
2
+ import { useElementSetting } from '@elementor/editor-elements';
3
+
4
+ import {
5
+ componentInstancePropTypeUtil,
6
+ type ComponentInstancePropValue,
7
+ } from '../prop-types/component-instance-prop-type';
8
+
9
+ export function useComponentInstanceSettings() {
10
+ const { element } = useElement();
11
+
12
+ const settings = useElementSetting< ComponentInstancePropValue >( element.id, 'component_instance' );
13
+
14
+ return componentInstancePropTypeUtil.extract( settings );
15
+ }
@@ -1,9 +1,9 @@
1
1
  import { useCallback } from 'react';
2
2
  import { getV1DocumentsManager } from '@elementor/editor-documents';
3
- import { __privateRunCommand as runCommand } from '@elementor/editor-v1-adapters';
4
3
  import { __useSelector as useSelector } from '@elementor/store';
5
4
 
6
5
  import { selectPath } from '../store/store';
6
+ import { switchToComponent } from '../utils/switch-to-component';
7
7
 
8
8
  export function useNavigateBack() {
9
9
  const path = useSelector( selectPath );
@@ -13,22 +13,12 @@ export function useNavigateBack() {
13
13
  return useCallback( () => {
14
14
  const { componentId: prevComponentId, instanceId: prevComponentInstanceId } = path.at( -2 ) ?? {};
15
15
 
16
- const switchToDocument = ( id: number, selector?: string ) => {
17
- runCommand( 'editor/documents/switch', {
18
- id,
19
- selector,
20
- mode: 'autosave',
21
- setAsInitial: false,
22
- shouldScroll: false,
23
- } );
24
- };
25
-
26
16
  if ( prevComponentId && prevComponentInstanceId ) {
27
- switchToDocument( prevComponentId, `[data-id="${ prevComponentInstanceId }"]` );
17
+ switchToComponent( prevComponentId, prevComponentInstanceId );
28
18
 
29
19
  return;
30
20
  }
31
21
 
32
- switchToDocument( documentsManager.getInitialId() );
22
+ switchToComponent( documentsManager.getInitialId() );
33
23
  }, [ path, documentsManager ] );
34
24
  }
package/src/init.ts CHANGED
@@ -9,6 +9,7 @@ import {
9
9
  FIELD_TYPE,
10
10
  injectIntoPanelHeaderTop,
11
11
  registerControlReplacement,
12
+ registerEditingPanelReplacement,
12
13
  registerFieldIndicator,
13
14
  } from '@elementor/editor-editing-panel';
14
15
  import { type V1ElementData } from '@elementor/editor-elements';
@@ -26,6 +27,7 @@ import { COMPONENT_DOCUMENT_TYPE } from './components/consts';
26
27
  import { CreateComponentForm } from './components/create-component-form/create-component-form';
27
28
  import { EditComponent } from './components/edit-component/edit-component';
28
29
  import { openEditModeDialog } from './components/in-edit-mode';
30
+ import { InstanceEditingPanel } from './components/instance-editing-panel/instance-editing-panel';
29
31
  import { OverridablePropControl } from './components/overridable-props/overridable-prop-control';
30
32
  import { OverridablePropIndicator } from './components/overridable-props/overridable-prop-indicator';
31
33
  import { createComponentType, TYPE } from './create-component-type';
@@ -109,6 +111,12 @@ export function init() {
109
111
  condition: ( { value } ) => componentOverridablePropTypeUtil.isValid( value ),
110
112
  } );
111
113
 
114
+ registerEditingPanelReplacement( {
115
+ id: 'component-instance-edit-panel',
116
+ condition: ( _, elementType ) => elementType.key === 'e-component',
117
+ component: InstanceEditingPanel,
118
+ } );
119
+
112
120
  settingsTransformersRegistry.register( 'component-instance', componentInstanceTransformer );
113
121
  settingsTransformersRegistry.register( 'overridable', componentOverridableTransformer );
114
122
 
@@ -0,0 +1,18 @@
1
+ import { createPropUtils } from '@elementor/editor-props';
2
+ import { z } from '@elementor/schema';
3
+
4
+ export const componentInstanceOverridePropTypeUtil = createPropUtils(
5
+ 'override',
6
+ z.object( {
7
+ override_key: z.string(),
8
+ override_value: z.unknown(),
9
+ schema_source: z.object( {
10
+ type: z.literal( 'component' ),
11
+ id: z.number(),
12
+ } ),
13
+ } )
14
+ );
15
+
16
+ export type ComponentInstanceOverridePropValue = z.infer<
17
+ typeof componentInstanceOverridePropTypeUtil.schema
18
+ >[ 'value' ];
@@ -0,0 +1,13 @@
1
+ import { createPropUtils } from '@elementor/editor-props';
2
+ import { z } from '@elementor/schema';
3
+
4
+ import { componentInstanceOverridePropTypeUtil } from './component-instance-override-prop-type';
5
+
6
+ export const componentInstanceOverridesPropTypeUtil = createPropUtils(
7
+ 'overrides',
8
+ z.array( componentInstanceOverridePropTypeUtil.schema )
9
+ );
10
+
11
+ export type ComponentInstanceOverridesPropValue = z.infer<
12
+ typeof componentInstanceOverridesPropTypeUtil.schema
13
+ >[ 'value' ];
@@ -0,0 +1,14 @@
1
+ import { createPropUtils, numberPropTypeUtil } from '@elementor/editor-props';
2
+ import { z } from '@elementor/schema';
3
+
4
+ import { componentInstanceOverridesPropTypeUtil } from './component-instance-overrides-prop-type';
5
+
6
+ export const componentInstancePropTypeUtil = createPropUtils(
7
+ 'component-instance',
8
+ z.object( {
9
+ component_id: numberPropTypeUtil.schema,
10
+ overrides: componentInstanceOverridesPropTypeUtil.schema,
11
+ } )
12
+ );
13
+
14
+ export type ComponentInstancePropValue = z.infer< typeof componentInstancePropTypeUtil.schema >[ 'value' ];
@@ -133,7 +133,7 @@ const selectUnpublishedData = ( state: ComponentsSlice ) => state[ SLICE_NAME ].
133
133
  const getCreatedThisSession = ( state: ComponentsSlice ) => state[ SLICE_NAME ].createdThisSession;
134
134
  const getPath = ( state: ComponentsSlice ) => state[ SLICE_NAME ].path;
135
135
  const getCurrentComponentId = ( state: ComponentsSlice ) => state[ SLICE_NAME ].currentComponentId;
136
- const selectComponent = ( state: ComponentsSlice, componentId: ComponentId ) =>
136
+ export const selectComponent = ( state: ComponentsSlice, componentId: ComponentId ) =>
137
137
  state[ SLICE_NAME ].data.find( ( component ) => component.id === componentId );
138
138
 
139
139
  export const selectComponents = createSelector(
@@ -0,0 +1,11 @@
1
+ import { __privateRunCommand as runCommand } from '@elementor/editor-v1-adapters';
2
+
3
+ export function switchToComponent( componentId: number | string, componentInstanceId?: string | null ) {
4
+ runCommand( 'editor/documents/switch', {
5
+ id: componentId,
6
+ selector: componentInstanceId ? `[data-id="${ componentInstanceId }"]` : undefined,
7
+ mode: 'autosave',
8
+ setAsInitial: false,
9
+ shouldScroll: false,
10
+ } );
11
+ }