@elementor/editor-components 4.0.0-607 → 4.0.0-619

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.
Files changed (33) hide show
  1. package/dist/index.d.mts +4 -1
  2. package/dist/index.d.ts +4 -1
  3. package/dist/index.js +2380 -2216
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +2835 -2680
  6. package/dist/index.mjs.map +1 -1
  7. package/package.json +23 -23
  8. package/src/components/components-tab/components-item.tsx +84 -215
  9. package/src/components/components-tab/components-list.tsx +3 -3
  10. package/src/components/components-tab/components.tsx +1 -2
  11. package/src/components/instance-editing-panel/empty-state.tsx +2 -2
  12. package/src/components/instance-editing-panel/instance-editing-panel.tsx +19 -78
  13. package/src/components/instance-editing-panel/instance-panel-body.tsx +36 -0
  14. package/src/components/instance-editing-panel/instance-panel-header.tsx +40 -0
  15. package/src/components/instance-editing-panel/override-prop-control.tsx +5 -3
  16. package/src/components/instance-editing-panel/use-instance-panel-data.ts +51 -0
  17. package/src/create-component-type.ts +15 -13
  18. package/src/extended/components/component-properties-panel/component-properties-panel.tsx +9 -17
  19. package/src/extended/components/components-tab/component-item.tsx +180 -0
  20. package/src/extended/components/components-tab/components.tsx +58 -0
  21. package/src/extended/components/create-component-form/create-component-form.tsx +1 -1
  22. package/src/extended/components/instance-editing-panel/instance-editing-panel.tsx +60 -0
  23. package/src/extended/init.ts +22 -1
  24. package/src/{store → extended/store}/actions/archive-component.ts +1 -1
  25. package/src/{store → extended/store}/actions/rename-component.ts +2 -2
  26. package/src/{utils → extended/utils}/component-name-validation.ts +1 -1
  27. package/src/extended/utils/replace-element-with-component.ts +1 -1
  28. package/src/index.ts +1 -0
  29. package/src/utils/is-pro-user.ts +6 -21
  30. /package/src/{components → extended/components}/components-tab/delete-confirmation-dialog.tsx +0 -0
  31. /package/src/{utils → extended/utils}/component-form-schema.ts +0 -0
  32. /package/src/{utils → extended/utils}/create-component-model.ts +0 -0
  33. /package/src/{utils → extended/utils}/get-container-for-new-element.ts +0 -0
@@ -0,0 +1,51 @@
1
+ import { useElement } from '@elementor/editor-editing-panel';
2
+
3
+ import { useSanitizeOverridableProps } from '../../hooks/use-sanitize-overridable-props';
4
+ import { type ComponentInstanceOverridesPropValue } from '../../prop-types/component-instance-overrides-prop-type';
5
+ import { componentInstancePropTypeUtil } from '../../prop-types/component-instance-prop-type';
6
+ import { useComponent } from '../../store/store';
7
+ import { type Component, type OverridablePropsGroup } from '../../types';
8
+
9
+ type InstancePanelData = {
10
+ componentId: number;
11
+ component: Component;
12
+ overrides: ComponentInstanceOverridesPropValue;
13
+ overridableProps: NonNullable< ReturnType< typeof useSanitizeOverridableProps > >;
14
+ groups: OverridablePropsGroup[];
15
+ isEmpty: boolean;
16
+ componentInstanceId: string | undefined;
17
+ };
18
+
19
+ export function useInstancePanelData(): InstancePanelData | null {
20
+ const { element, settings } = useComponentInstanceSettings();
21
+
22
+ const componentId = settings?.component_id?.value;
23
+
24
+ const overrides = settings?.overrides?.value;
25
+
26
+ const component = useComponent( componentId ?? null );
27
+
28
+ const componentInstanceId = element?.id;
29
+
30
+ const overridableProps = useSanitizeOverridableProps( componentId ?? null, componentInstanceId );
31
+
32
+ if ( ! componentId || ! overridableProps || ! component ) {
33
+ return null;
34
+ }
35
+
36
+ const isNonEmptyGroup = ( group: OverridablePropsGroup | null ) => group !== null && group.props.length > 0;
37
+
38
+ const groups = overridableProps.groups.order
39
+ .map( ( groupId ) => overridableProps.groups.items[ groupId ] ?? null )
40
+ .filter( isNonEmptyGroup );
41
+
42
+ const isEmpty = groups.length === 0 || Object.keys( overridableProps.props ).length === 0;
43
+
44
+ return { componentId, component, overrides, overridableProps, groups, isEmpty, componentInstanceId };
45
+ }
46
+
47
+ function useComponentInstanceSettings() {
48
+ const { element, settings } = useElement();
49
+
50
+ return { element, settings: componentInstancePropTypeUtil.extract( settings.component_instance ) };
51
+ }
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  type BackboneModel,
3
3
  type BackboneModelConstructor,
4
+ type ContextMenuAction,
4
5
  type CreateTemplatedElementTypeOptions,
5
6
  createTemplatedElementView,
6
7
  type ElementModel,
@@ -20,19 +21,12 @@ import { type ComponentInstanceProp } from './prop-types/component-instance-prop
20
21
  import { type ComponentsSlice, selectComponentByUid } from './store/store';
21
22
  import { type ComponentRenderContext, type ExtendedWindow } from './types';
22
23
  import { formatComponentElementsId } from './utils/format-component-elements-id';
24
+ import { hasProInstalled } from './utils/is-pro-user';
23
25
  import { switchToComponent } from './utils/switch-to-component';
24
26
  import { trackComponentEvent } from './utils/tracking';
25
27
 
26
28
  type ContextMenuEventData = { location: string; secondaryLocation: string; trigger: string };
27
29
 
28
- export type ContextMenuAction = {
29
- name: string;
30
- icon: string;
31
- title: string | ( () => string );
32
- isEnabled: () => boolean;
33
- callback: ( _: unknown, eventData: ContextMenuEventData ) => void;
34
- };
35
-
36
30
  type ContextMenuGroupConfig = {
37
31
  disable: Record< string, string[] >;
38
32
  add: Record< string, { index: number; action: ContextMenuAction } >;
@@ -58,6 +52,8 @@ type ComponentModelInstance = BackboneModel< ComponentModel > & {
58
52
 
59
53
  export const COMPONENT_WIDGET_TYPE = 'e-component';
60
54
 
55
+ const EDIT_COMPONENT_UPGRADE_URL = 'https://go.elementor.com/go-pro-components-edit/';
56
+
61
57
  const updateGroups = ( groups: ContextMenuGroup[], config: ContextMenuGroupConfig ): ContextMenuGroup[] => {
62
58
  const disableMap = new Map( Object.entries( config.disable ?? {} ) );
63
59
  const addMap = new Map( Object.entries( config.add ?? {} ) );
@@ -218,6 +214,11 @@ function createComponentView(
218
214
 
219
215
  _getContextMenuConfig() {
220
216
  const isAdministrator = isUserAdministrator();
217
+ const hasPro = hasProInstalled();
218
+
219
+ const proLabel = __( 'PRO', 'elementor' );
220
+ const badgeClass = 'elementor-context-menu-list__item__shortcut__new-badge';
221
+ const proBadge = `<a href="${ EDIT_COMPONENT_UPGRADE_URL }" target="_blank" onclick="event.stopPropagation()" class="${ badgeClass }">${ proLabel }</a>`;
221
222
 
222
223
  const addedGroup = {
223
224
  general: {
@@ -226,7 +227,8 @@ function createComponentView(
226
227
  name: 'edit component',
227
228
  icon: 'eicon-edit',
228
229
  title: () => __( 'Edit Component', 'elementor' ),
229
- isEnabled: () => true,
230
+ ...( ! hasPro && { shortcut: proBadge, hasShortcutAction: true } ),
231
+ isEnabled: () => hasPro,
230
232
  callback: ( _: unknown, eventData: ContextMenuEventData ) => this.editComponent( eventData ),
231
233
  },
232
234
  },
@@ -253,7 +255,9 @@ function createComponentView(
253
255
  }
254
256
 
255
257
  editComponent( { trigger, location, secondaryLocation }: ContextMenuEventData ) {
256
- if ( this.isComponentCurrentlyEdited() ) {
258
+ const hasPro = hasProInstalled();
259
+
260
+ if ( ! hasPro || this.isComponentCurrentlyEdited() ) {
257
261
  return;
258
262
  }
259
263
 
@@ -275,9 +279,7 @@ function createComponentView(
275
279
  handleDblClick( e: MouseEvent ) {
276
280
  e.stopPropagation();
277
281
 
278
- const isAdministrator = isUserAdministrator();
279
-
280
- if ( ! isAdministrator ) {
282
+ if ( ! isUserAdministrator() || ! hasProInstalled() ) {
281
283
  return;
282
284
  }
283
285
 
@@ -1,6 +1,5 @@
1
1
  import * as React from 'react';
2
- import { ElementProvider, usePanelActions as useEditingPanelActions } from '@elementor/editor-editing-panel';
3
- import { useSelectedElement } from '@elementor/editor-elements';
2
+ import { usePanelActions as useEditingPanelActions } from '@elementor/editor-editing-panel';
4
3
  import { __createPanel as createPanel, Panel } from '@elementor/editor-panels';
5
4
  import { ThemeProvider } from '@elementor/editor-ui';
6
5
  import { Alert, Box, ErrorBoundary } from '@elementor/ui';
@@ -16,27 +15,20 @@ export const { panel, usePanelActions } = createPanel( {
16
15
  } );
17
16
 
18
17
  function ComponentPropertiesPanel() {
19
- const { element, elementType } = useSelectedElement();
20
18
  const { close: closePanel } = usePanelActions();
21
19
  const { open: openEditingPanel } = useEditingPanelActions();
22
20
 
23
- if ( ! element || ! elementType ) {
24
- return null;
25
- }
26
-
27
21
  return (
28
22
  <ThemeProvider>
29
23
  <ErrorBoundary fallback={ <ErrorBoundaryFallback /> }>
30
- <ElementProvider element={ element } elementType={ elementType }>
31
- <Panel>
32
- <ComponentPropertiesPanelContent
33
- onClose={ () => {
34
- closePanel();
35
- openEditingPanel();
36
- } }
37
- />
38
- </Panel>
39
- </ElementProvider>
24
+ <Panel>
25
+ <ComponentPropertiesPanelContent
26
+ onClose={ () => {
27
+ closePanel();
28
+ openEditingPanel();
29
+ } }
30
+ />
31
+ </Panel>
40
32
  </ErrorBoundary>
41
33
  </ThemeProvider>
42
34
  );
@@ -0,0 +1,180 @@
1
+ import * as React from 'react';
2
+ import { useRef, useState } from 'react';
3
+ import { endDragElementFromPanel, startDragElementFromPanel } from '@elementor/editor-canvas';
4
+ import { dropElement, type DropElementParams, type V1ElementData } from '@elementor/editor-elements';
5
+ import { MenuListItem, useEditable, WarningInfotip } from '@elementor/editor-ui';
6
+ import { DotsVerticalIcon } from '@elementor/icons';
7
+ import { bindMenu, bindTrigger, IconButton, Menu, Stack, usePopupState } from '@elementor/ui';
8
+ import { __ } from '@wordpress/i18n';
9
+
10
+ import {
11
+ ComponentItem as CoreComponentItem,
12
+ type ComponentItemProps,
13
+ ComponentName,
14
+ } from '../../../components/components-tab/components-item';
15
+ import { useComponentsPermissions } from '../../../hooks/use-components-permissions';
16
+ import { loadComponentsAssets } from '../../../store/actions/load-components-assets';
17
+ import { archiveComponent } from '../../store/actions/archive-component';
18
+ import { renameComponent } from '../../store/actions/rename-component';
19
+ import { validateComponentName } from '../../utils/component-name-validation';
20
+ import { createComponentModel } from '../../utils/create-component-model';
21
+ import { getContainerForNewElement } from '../../utils/get-container-for-new-element';
22
+ import { DeleteConfirmationDialog } from './delete-confirmation-dialog';
23
+
24
+ export function ComponentItem( { component }: ComponentItemProps ) {
25
+ const itemRef = useRef< HTMLElement >( null );
26
+ const [ isDeleteDialogOpen, setIsDeleteDialogOpen ] = useState( false );
27
+ const { canRename, canDelete } = useComponentsPermissions();
28
+
29
+ const shouldShowActions = canRename || canDelete;
30
+
31
+ const {
32
+ ref: editableRef,
33
+ isEditing,
34
+ openEditMode,
35
+ error,
36
+ getProps: getEditableProps,
37
+ } = useEditable( {
38
+ value: component.name,
39
+ onSubmit: ( newName: string ) => renameComponent( component.uid, newName ),
40
+ validation: validateComponentTitle,
41
+ } );
42
+
43
+ const componentModel = createComponentModel( component );
44
+
45
+ const popupState = usePopupState( {
46
+ variant: 'popover',
47
+ disableAutoFocus: true,
48
+ } );
49
+
50
+ const handleClick = () => {
51
+ addComponentToPage( componentModel );
52
+ };
53
+
54
+ const handleDragEnd = () => {
55
+ loadComponentsAssets( [ componentModel as V1ElementData ] );
56
+
57
+ endDragElementFromPanel();
58
+ };
59
+
60
+ const handleDeleteClick = () => {
61
+ setIsDeleteDialogOpen( true );
62
+ popupState.close();
63
+ };
64
+
65
+ const handleDeleteConfirm = () => {
66
+ if ( ! component.id ) {
67
+ throw new Error( 'Component ID is required' );
68
+ }
69
+
70
+ setIsDeleteDialogOpen( false );
71
+ archiveComponent( component.id, component.name );
72
+ };
73
+
74
+ const handleDeleteDialogClose = () => {
75
+ setIsDeleteDialogOpen( false );
76
+ };
77
+
78
+ return (
79
+ <Stack>
80
+ <WarningInfotip
81
+ open={ Boolean( error ) }
82
+ text={ error ?? '' }
83
+ placement="bottom"
84
+ width={ itemRef.current?.getBoundingClientRect().width }
85
+ offset={ [ 0, -15 ] }
86
+ >
87
+ <CoreComponentItem
88
+ ref={ itemRef }
89
+ component={ component }
90
+ disabled={ false }
91
+ draggable
92
+ onDragStart={ ( event: React.DragEvent ) => startDragElementFromPanel( componentModel, event ) }
93
+ onDragEnd={ handleDragEnd }
94
+ onClick={ handleClick }
95
+ isEditing={ isEditing }
96
+ error={ error }
97
+ nameSlot={
98
+ <ComponentName
99
+ name={ component.name }
100
+ editable={ { ref: editableRef, isEditing, getProps: getEditableProps } }
101
+ />
102
+ }
103
+ endSlot={
104
+ shouldShowActions ? (
105
+ <IconButton size="tiny" { ...bindTrigger( popupState ) } aria-label="More actions">
106
+ <DotsVerticalIcon fontSize="tiny" />
107
+ </IconButton>
108
+ ) : undefined
109
+ }
110
+ />
111
+ </WarningInfotip>
112
+ { shouldShowActions && (
113
+ <Menu
114
+ { ...bindMenu( popupState ) }
115
+ anchorOrigin={ {
116
+ vertical: 'bottom',
117
+ horizontal: 'right',
118
+ } }
119
+ transformOrigin={ {
120
+ vertical: 'top',
121
+ horizontal: 'right',
122
+ } }
123
+ >
124
+ { canRename && (
125
+ <MenuListItem
126
+ sx={ { minWidth: '160px' } }
127
+ primaryTypographyProps={ { variant: 'caption', color: 'text.primary' } }
128
+ onClick={ () => {
129
+ popupState.close();
130
+ openEditMode();
131
+ } }
132
+ >
133
+ { __( 'Rename', 'elementor' ) }
134
+ </MenuListItem>
135
+ ) }
136
+ { canDelete && (
137
+ <MenuListItem
138
+ sx={ { minWidth: '160px' } }
139
+ primaryTypographyProps={ { variant: 'caption', color: 'error.light' } }
140
+ onClick={ handleDeleteClick }
141
+ >
142
+ { __( 'Delete', 'elementor' ) }
143
+ </MenuListItem>
144
+ ) }
145
+ </Menu>
146
+ ) }
147
+ <DeleteConfirmationDialog
148
+ open={ isDeleteDialogOpen }
149
+ onClose={ handleDeleteDialogClose }
150
+ onConfirm={ handleDeleteConfirm }
151
+ />
152
+ </Stack>
153
+ );
154
+ }
155
+
156
+ const addComponentToPage = ( model: DropElementParams[ 'model' ] ) => {
157
+ const { container, options } = getContainerForNewElement();
158
+
159
+ if ( ! container ) {
160
+ throw new Error( `Can't find container to drop new component instance at` );
161
+ }
162
+
163
+ loadComponentsAssets( [ model as V1ElementData ] );
164
+
165
+ dropElement( {
166
+ containerId: container.id,
167
+ model,
168
+ options: { ...options, useHistory: false, scrollIntoView: true },
169
+ } );
170
+ };
171
+
172
+ const validateComponentTitle = ( newTitle: string ) => {
173
+ const result = validateComponentName( newTitle );
174
+
175
+ if ( ! result.errorMessage ) {
176
+ return null;
177
+ }
178
+
179
+ return result.errorMessage;
180
+ };
@@ -0,0 +1,58 @@
1
+ import * as React from 'react';
2
+ import { ThemeProvider } from '@elementor/editor-ui';
3
+ import { List } from '@elementor/ui';
4
+
5
+ import { ComponentSearch } from '../../../components/components-tab/component-search';
6
+ import {
7
+ EmptySearchResult,
8
+ EmptyState,
9
+ useFilteredComponents,
10
+ } from '../../../components/components-tab/components-list';
11
+ import { LoadingComponents } from '../../../components/components-tab/loading-components';
12
+ import { SearchProvider } from '../../../components/components-tab/search-provider';
13
+ import { useComponents } from '../../../hooks/use-components';
14
+ import { ComponentItem } from './component-item';
15
+
16
+ const ExtendedComponentsList = () => {
17
+ const { components, isLoading, searchValue } = useFilteredComponents();
18
+
19
+ if ( isLoading ) {
20
+ return <LoadingComponents />;
21
+ }
22
+
23
+ const isEmpty = ! components?.length;
24
+
25
+ if ( isEmpty ) {
26
+ return searchValue.length ? <EmptySearchResult /> : <EmptyState />;
27
+ }
28
+
29
+ return (
30
+ <List sx={ { display: 'flex', flexDirection: 'column', gap: 1, px: 2 } }>
31
+ { components.map( ( component ) => (
32
+ <ComponentItem key={ component.uid } component={ component } />
33
+ ) ) }
34
+ </List>
35
+ );
36
+ };
37
+
38
+ const ExtendedComponentsContent = () => {
39
+ const { components, isLoading } = useComponents();
40
+ const hasComponents = ! isLoading && components.length > 0;
41
+
42
+ return (
43
+ <>
44
+ { hasComponents && <ComponentSearch /> }
45
+ <ExtendedComponentsList />
46
+ </>
47
+ );
48
+ };
49
+
50
+ export const ExtendedComponents = () => {
51
+ return (
52
+ <ThemeProvider>
53
+ <SearchProvider localStorageKey="elementor-components-search">
54
+ <ExtendedComponentsContent />
55
+ </SearchProvider>
56
+ </ThemeProvider>
57
+ );
58
+ };
@@ -11,11 +11,11 @@ import { __ } from '@wordpress/i18n';
11
11
  import { useComponents } from '../../../hooks/use-components';
12
12
  import { selectComponentByUid } from '../../../store/store';
13
13
  import { type ComponentFormValues, type PublishedComponent } from '../../../types';
14
- import { createBaseComponentSchema, createSubmitComponentSchema } from '../../../utils/component-form-schema';
15
14
  import { switchToComponent } from '../../../utils/switch-to-component';
16
15
  import { trackComponentEvent } from '../../../utils/tracking';
17
16
  import { createUnpublishedComponent } from '../../store/actions/create-unpublished-component';
18
17
  import { findNonAtomicElementsInElement } from '../../sync/prevent-non-atomic-nesting';
18
+ import { createBaseComponentSchema, createSubmitComponentSchema } from '../../utils/component-form-schema';
19
19
  import { useForm } from './hooks/use-form';
20
20
  import {
21
21
  type ComponentEventData,
@@ -0,0 +1,60 @@
1
+ import * as React from 'react';
2
+ import { PencilIcon } from '@elementor/icons';
3
+ import { Box } from '@elementor/ui';
4
+ import { __ } from '@wordpress/i18n';
5
+
6
+ import { EmptyState } from '../../../components/instance-editing-panel/empty-state';
7
+ import { InstancePanelBody } from '../../../components/instance-editing-panel/instance-panel-body';
8
+ import {
9
+ EditComponentAction,
10
+ InstancePanelHeader,
11
+ } from '../../../components/instance-editing-panel/instance-panel-header';
12
+ import { useInstancePanelData } from '../../../components/instance-editing-panel/use-instance-panel-data';
13
+ import { useComponentsPermissions } from '../../../hooks/use-components-permissions';
14
+ import { ComponentInstanceProvider } from '../../../provider/component-instance-context';
15
+ import { switchToComponent } from '../../../utils/switch-to-component';
16
+
17
+ export function ExtendedInstanceEditingPanel() {
18
+ const { canEdit } = useComponentsPermissions();
19
+ const data = useInstancePanelData();
20
+
21
+ if ( ! data ) {
22
+ return null;
23
+ }
24
+
25
+ const { componentId, component, overrides, overridableProps, groups, isEmpty, componentInstanceId } = data;
26
+
27
+ /* translators: %s: component name. */
28
+ const panelTitle = __( 'Edit %s', 'elementor' ).replace( '%s', component.name );
29
+
30
+ const handleEditComponent = () => switchToComponent( componentId, componentInstanceId );
31
+
32
+ return (
33
+ <Box data-testid="instance-editing-panel">
34
+ <ComponentInstanceProvider
35
+ componentId={ componentId }
36
+ overrides={ overrides }
37
+ overridableProps={ overridableProps }
38
+ >
39
+ <InstancePanelHeader
40
+ componentName={ component.name }
41
+ actions={
42
+ canEdit ? (
43
+ <EditComponentAction
44
+ label={ panelTitle }
45
+ onClick={ handleEditComponent }
46
+ icon={ PencilIcon }
47
+ />
48
+ ) : undefined
49
+ }
50
+ />
51
+ <InstancePanelBody
52
+ groups={ groups }
53
+ isEmpty={ isEmpty }
54
+ emptyState={ <EmptyState onEditComponent={ canEdit ? handleEditComponent : undefined } /> }
55
+ componentInstanceId={ componentInstanceId }
56
+ />
57
+ </ComponentInstanceProvider>
58
+ </Box>
59
+ );
60
+ }
@@ -1,17 +1,26 @@
1
1
  import { injectIntoLogic, injectIntoTop } from '@elementor/editor';
2
2
  import { registerControlReplacement } from '@elementor/editor-controls';
3
3
  import { getV1CurrentDocument } from '@elementor/editor-documents';
4
- import { FIELD_TYPE, injectIntoPanelHeaderTop, registerFieldIndicator } from '@elementor/editor-editing-panel';
4
+ import {
5
+ FIELD_TYPE,
6
+ injectIntoPanelHeaderTop,
7
+ registerEditingPanelReplacement,
8
+ registerFieldIndicator,
9
+ } from '@elementor/editor-editing-panel';
10
+ import { registerTab } from '@elementor/editor-elements-panel';
5
11
  import { __registerPanel as registerPanel } from '@elementor/editor-panels';
6
12
  import { registerDataHook } from '@elementor/editor-v1-adapters';
13
+ import { __ } from '@wordpress/i18n';
7
14
 
8
15
  import { componentOverridablePropTypeUtil } from '../prop-types/component-overridable-prop-type';
9
16
  import { type ExtendedWindow } from '../types';
10
17
  import { onElementDrop } from '../utils/tracking';
11
18
  import { ComponentPanelHeader } from './components/component-panel-header/component-panel-header';
12
19
  import { panel as componentPropertiesPanel } from './components/component-properties-panel/component-properties-panel';
20
+ import { ExtendedComponents } from './components/components-tab/components';
13
21
  import { CreateComponentForm } from './components/create-component-form/create-component-form';
14
22
  import { EditComponent } from './components/edit-component/edit-component';
23
+ import { ExtendedInstanceEditingPanel } from './components/instance-editing-panel/instance-editing-panel';
15
24
  import { OverridablePropControl } from './components/overridable-props/overridable-prop-control';
16
25
  import { OverridablePropIndicator } from './components/overridable-props/overridable-prop-indicator';
17
26
  import { COMPONENT_DOCUMENT_TYPE, OVERRIDABLE_PROP_REPLACEMENT_ID } from './consts';
@@ -24,6 +33,18 @@ import { initRevertOverridablesOnCopyOrDuplicate } from './sync/revert-overridab
24
33
  import { SanitizeOverridableProps } from './sync/sanitize-overridable-props';
25
34
 
26
35
  export function initExtended() {
36
+ registerEditingPanelReplacement( {
37
+ id: 'component-instance-edit-panel',
38
+ condition: ( _, elementType ) => elementType.key === 'e-component',
39
+ component: ExtendedInstanceEditingPanel,
40
+ } );
41
+
42
+ registerTab( {
43
+ id: 'components',
44
+ label: __( 'Components', 'elementor' ),
45
+ component: ExtendedComponents,
46
+ } );
47
+
27
48
  registerPanel( componentPropertiesPanel );
28
49
 
29
50
  registerDataHook( 'dependency', 'editor/documents/close', ( args ) => {
@@ -3,7 +3,7 @@ import { type NotificationData, notify } from '@elementor/editor-notifications';
3
3
  import { __dispatch as dispatch } from '@elementor/store';
4
4
  import { __ } from '@wordpress/i18n';
5
5
 
6
- import { slice } from '../store';
6
+ import { slice } from '../../../store/store';
7
7
 
8
8
  const successNotification = ( componentId: number, componentName: string ): NotificationData => ( {
9
9
  type: 'success',
@@ -2,8 +2,8 @@ import { getV1DocumentsManager, setDocumentModifiedStatus } from '@elementor/edi
2
2
  import { getAllDescendants, type V1Element } from '@elementor/editor-elements';
3
3
  import { __dispatch as dispatch } from '@elementor/store';
4
4
 
5
- import { COMPONENT_WIDGET_TYPE } from '../../create-component-type';
6
- import { slice } from '../store';
5
+ import { COMPONENT_WIDGET_TYPE } from '../../../create-component-type';
6
+ import { slice } from '../../../store/store';
7
7
 
8
8
  const TITLE_EXTERNAL_CHANGE_COMMAND = 'title_external_change';
9
9
 
@@ -1,6 +1,6 @@
1
1
  import { __getState as getState } from '@elementor/store';
2
2
 
3
- import { selectComponents } from '../store/store';
3
+ import { selectComponents } from '../../store/store';
4
4
  import { createSubmitComponentSchema } from './component-form-schema';
5
5
 
6
6
  type ValidationResult = { isValid: true; errorMessage: null } | { isValid: false; errorMessage: string };
@@ -1,6 +1,6 @@
1
1
  import { replaceElement, type V1ElementData } from '@elementor/editor-elements';
2
2
 
3
- import { type ComponentInstanceParams, createComponentModel } from '../../utils/create-component-model';
3
+ import { type ComponentInstanceParams, createComponentModel } from './create-component-model';
4
4
 
5
5
  export const replaceElementWithComponent = async ( element: V1ElementData, component: ComponentInstanceParams ) => {
6
6
  return await replaceElement( {
package/src/index.ts CHANGED
@@ -1 +1,2 @@
1
1
  export { init } from './init';
2
+ export { hasProInstalled, isProActive } from './utils/is-pro-user';
@@ -1,26 +1,11 @@
1
- type ExtendedWindow = Window & {
2
- elementor?: {
3
- helpers?: {
4
- hasPro?: () => boolean;
5
- };
6
- };
7
- elementorPro?: {
8
- config?: {
9
- isActive?: boolean;
10
- };
11
- };
12
- };
13
-
14
- export function isProUser(): boolean {
15
- const extendedWindow = window as unknown as ExtendedWindow;
16
-
17
- const hasPro = extendedWindow.elementor?.helpers?.hasPro?.() ?? false;
1
+ export function hasProInstalled(): boolean {
2
+ return window.elementor?.helpers?.hasPro?.() ?? false;
3
+ }
18
4
 
19
- if ( ! hasPro ) {
5
+ export function isProActive(): boolean {
6
+ if ( ! hasProInstalled() ) {
20
7
  return false;
21
8
  }
22
9
 
23
- const isProActive = extendedWindow.elementorPro?.config?.isActive ?? false;
24
-
25
- return isProActive;
10
+ return window.elementorPro?.config?.isActive ?? false;
26
11
  }