@elementor/editor-components 4.0.0-665 → 4.0.0-667
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.js +191 -3870
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +184 -3904
- package/dist/index.mjs.map +1 -1
- package/package.json +23 -23
- package/src/init.ts +0 -13
- 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 -281
- 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 -108
- package/src/extended/mcp/index.ts +0 -14
- package/src/extended/mcp/save-as-component-tool.ts +0 -436
- package/src/extended/shortcuts/create-component-shortcut.ts +0 -121
- package/src/extended/store/actions/add-overridable-group.ts +0 -53
- package/src/extended/store/actions/archive-component.ts +0 -18
- package/src/extended/store/actions/create-unpublished-component.ts +0 -99
- package/src/extended/store/actions/delete-overridable-group.ts +0 -32
- package/src/extended/store/actions/delete-overridable-prop.ts +0 -64
- package/src/extended/store/actions/rename-component.ts +0 -48
- package/src/extended/store/actions/rename-overridable-group.ts +0 -33
- package/src/extended/store/actions/reorder-group-props.ts +0 -37
- package/src/extended/store/actions/reorder-overridable-groups.ts +0 -24
- package/src/extended/store/actions/reset-sanitized-components.ts +0 -5
- package/src/extended/store/actions/set-overridable-prop.ts +0 -109
- package/src/extended/store/actions/update-component-sanitized-attribute.ts +0 -7
- package/src/extended/store/actions/update-current-component.ts +0 -12
- package/src/extended/store/actions/update-overridable-prop-params.ts +0 -52
- 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 -78
- package/src/extended/sync/create-components-before-save.ts +0 -111
- 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 -22
- package/src/extended/sync/update-archived-component-before-save.ts +0 -31
- package/src/extended/sync/update-component-title-before-save.ts +0 -18
- package/src/extended/utils/component-form-schema.ts +0 -32
- package/src/extended/utils/component-name-validation.ts +0 -25
- 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 -5
- package/src/extended/utils/replace-element-with-component.ts +0 -11
- package/src/extended/utils/revert-overridable-settings.ts +0 -207
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
import { isAtomicWidget } from '@elementor/editor-canvas';
|
|
2
|
-
import { getAllDescendants, getElementType, type V1Element } from '@elementor/editor-elements';
|
|
3
|
-
import { type NotificationData, notify } from '@elementor/editor-notifications';
|
|
4
|
-
import { blockCommand } from '@elementor/editor-v1-adapters';
|
|
5
|
-
import { __ } from '@wordpress/i18n';
|
|
6
|
-
|
|
7
|
-
import { type ExtendedWindow } from '../../types';
|
|
8
|
-
import { isEditingComponent } from '../utils/is-editing-component';
|
|
9
|
-
|
|
10
|
-
type CreateArgs = {
|
|
11
|
-
container?: V1Element;
|
|
12
|
-
model?: {
|
|
13
|
-
elType?: string;
|
|
14
|
-
widgetType?: string;
|
|
15
|
-
};
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
type MoveArgs = {
|
|
19
|
-
containers?: V1Element[];
|
|
20
|
-
container?: V1Element;
|
|
21
|
-
target?: V1Element;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
type PasteArgs = {
|
|
25
|
-
containers?: V1Element[];
|
|
26
|
-
container?: V1Element;
|
|
27
|
-
storageType?: string;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export type ClipboardElement = {
|
|
31
|
-
elType?: string;
|
|
32
|
-
widgetType?: string;
|
|
33
|
-
elements?: ClipboardElement[];
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
type StorageContent = {
|
|
37
|
-
clipboard?: {
|
|
38
|
-
elements?: ClipboardElement[];
|
|
39
|
-
};
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const NON_ATOMIC_ELEMENT_ALERT: NotificationData = {
|
|
43
|
-
type: 'default',
|
|
44
|
-
message: __( "This widget isn't compatible with components. Use atomic elements instead.", 'elementor' ),
|
|
45
|
-
id: 'non-atomic-element-blocked',
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
export function initNonAtomicNestingPrevention() {
|
|
49
|
-
blockCommand( {
|
|
50
|
-
command: 'document/elements/create',
|
|
51
|
-
condition: blockNonAtomicCreate,
|
|
52
|
-
} );
|
|
53
|
-
|
|
54
|
-
blockCommand( {
|
|
55
|
-
command: 'document/elements/move',
|
|
56
|
-
condition: blockNonAtomicMove,
|
|
57
|
-
} );
|
|
58
|
-
|
|
59
|
-
blockCommand( {
|
|
60
|
-
command: 'document/elements/paste',
|
|
61
|
-
condition: blockNonAtomicPaste,
|
|
62
|
-
} );
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export function isElementAtomic( elementType: string ): boolean {
|
|
66
|
-
return getElementType( elementType ) !== null;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function blockNonAtomicCreate( args: CreateArgs ): boolean {
|
|
70
|
-
if ( ! isEditingComponent() ) {
|
|
71
|
-
return false;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const { model } = args;
|
|
75
|
-
const elementType = model?.widgetType || model?.elType;
|
|
76
|
-
|
|
77
|
-
if ( ! elementType ) {
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if ( isElementAtomic( elementType ) ) {
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
notify( NON_ATOMIC_ELEMENT_ALERT );
|
|
86
|
-
return true;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function blockNonAtomicMove( args: MoveArgs ): boolean {
|
|
90
|
-
if ( ! isEditingComponent() ) {
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const { containers = [ args.container ] } = args;
|
|
95
|
-
|
|
96
|
-
const hasNonAtomicElement = containers.some( ( container ) => {
|
|
97
|
-
if ( ! container ) {
|
|
98
|
-
return false;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const allElements = getAllDescendants( container );
|
|
102
|
-
|
|
103
|
-
return allElements.some( ( element ) => ! isAtomicWidget( element ) );
|
|
104
|
-
} );
|
|
105
|
-
|
|
106
|
-
if ( hasNonAtomicElement ) {
|
|
107
|
-
notify( NON_ATOMIC_ELEMENT_ALERT );
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return hasNonAtomicElement;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function blockNonAtomicPaste( args: PasteArgs ): boolean {
|
|
114
|
-
if ( ! isEditingComponent() ) {
|
|
115
|
-
return false;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const { storageType } = args;
|
|
119
|
-
|
|
120
|
-
if ( storageType !== 'localstorage' ) {
|
|
121
|
-
return false;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const data = (
|
|
125
|
-
window as unknown as ExtendedWindow & { elementorCommon?: { storage?: { get: () => StorageContent } } }
|
|
126
|
-
)?.elementorCommon?.storage?.get();
|
|
127
|
-
|
|
128
|
-
if ( ! data?.clipboard?.elements ) {
|
|
129
|
-
return false;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const hasNonAtomicElement = hasNonAtomicElementsInTree( data.clipboard.elements );
|
|
133
|
-
|
|
134
|
-
if ( hasNonAtomicElement ) {
|
|
135
|
-
notify( NON_ATOMIC_ELEMENT_ALERT );
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return hasNonAtomicElement;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
export function hasNonAtomicElementsInTree( elements: ClipboardElement[] ): boolean {
|
|
142
|
-
for ( const element of elements ) {
|
|
143
|
-
const elementType = element.widgetType || element.elType;
|
|
144
|
-
|
|
145
|
-
if ( elementType && ! isElementAtomic( elementType ) ) {
|
|
146
|
-
return true;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if ( element.elements?.length ) {
|
|
150
|
-
if ( hasNonAtomicElementsInTree( element.elements ) ) {
|
|
151
|
-
return true;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
export function findNonAtomicElements( elements: ClipboardElement[] ): string[] {
|
|
160
|
-
const nonAtomicElements: string[] = [];
|
|
161
|
-
|
|
162
|
-
for ( const element of elements ) {
|
|
163
|
-
const elementType = element.widgetType || element.elType;
|
|
164
|
-
|
|
165
|
-
if ( elementType && ! isElementAtomic( elementType ) ) {
|
|
166
|
-
nonAtomicElements.push( elementType );
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if ( element.elements?.length ) {
|
|
170
|
-
nonAtomicElements.push( ...findNonAtomicElements( element.elements ) );
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
return [ ...new Set( nonAtomicElements ) ];
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
type V1ElementLike = {
|
|
178
|
-
elType?: string;
|
|
179
|
-
widgetType?: string;
|
|
180
|
-
elements?: V1ElementLike[];
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
export function findNonAtomicElementsInElement( element: V1ElementLike ): string[] {
|
|
184
|
-
const nonAtomicElements: string[] = [];
|
|
185
|
-
const elementType = element.widgetType || element.elType;
|
|
186
|
-
|
|
187
|
-
if ( elementType && ! isElementAtomic( elementType ) ) {
|
|
188
|
-
nonAtomicElements.push( elementType );
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if ( element.elements?.length ) {
|
|
192
|
-
for ( const child of element.elements ) {
|
|
193
|
-
nonAtomicElements.push( ...findNonAtomicElementsInElement( child ) );
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return [ ...new Set( nonAtomicElements ) ];
|
|
198
|
-
}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { type V1Element, type V1ElementData } from '@elementor/editor-elements';
|
|
2
|
-
import { registerDataHook } from '@elementor/editor-v1-adapters';
|
|
3
|
-
|
|
4
|
-
import { type ExtendedWindow } from '../../types';
|
|
5
|
-
import { isEditingComponent } from '../utils/is-editing-component';
|
|
6
|
-
import {
|
|
7
|
-
revertAllOverridablesInContainer,
|
|
8
|
-
revertAllOverridablesInElementData,
|
|
9
|
-
} from '../utils/revert-overridable-settings';
|
|
10
|
-
|
|
11
|
-
type CopyArgs = {
|
|
12
|
-
storageKey?: string;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
type ClipboardData = {
|
|
16
|
-
type: string;
|
|
17
|
-
siteurl: string;
|
|
18
|
-
elements: V1ElementData[];
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export function initRevertOverridablesOnCopyOrDuplicate() {
|
|
22
|
-
registerDataHook( 'after', 'document/elements/duplicate', ( _args, result: V1Element | V1Element[] ) => {
|
|
23
|
-
if ( ! isEditingComponent() ) {
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
revertOverridablesForDuplicatedElements( result );
|
|
28
|
-
} );
|
|
29
|
-
|
|
30
|
-
registerDataHook( 'after', 'document/elements/copy', ( args: CopyArgs ) => {
|
|
31
|
-
if ( ! isEditingComponent() ) {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
revertOverridablesInStorage( args.storageKey ?? 'clipboard' );
|
|
36
|
-
} );
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function revertOverridablesForDuplicatedElements( duplicatedElements: V1Element | V1Element[] ) {
|
|
40
|
-
const containers = Array.isArray( duplicatedElements ) ? duplicatedElements : [ duplicatedElements ];
|
|
41
|
-
|
|
42
|
-
containers.forEach( ( container ) => {
|
|
43
|
-
revertAllOverridablesInContainer( container );
|
|
44
|
-
} );
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function revertOverridablesInStorage( storageKey: string ) {
|
|
48
|
-
const storage = ( window as unknown as ExtendedWindow ).elementorCommon?.storage;
|
|
49
|
-
|
|
50
|
-
if ( ! storage ) {
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const storageData = storage.get< ClipboardData >( storageKey );
|
|
55
|
-
|
|
56
|
-
if ( ! storageData?.elements?.length ) {
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const elementsDataWithOverridablesReverted = storageData.elements.map( revertAllOverridablesInElementData );
|
|
61
|
-
|
|
62
|
-
storage.set( storageKey, {
|
|
63
|
-
...storageData,
|
|
64
|
-
elements: elementsDataWithOverridablesReverted,
|
|
65
|
-
} );
|
|
66
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { useEffect } from 'react';
|
|
2
|
-
|
|
3
|
-
import { useCurrentComponentId, useIsSanitizedComponent, useOverridableProps } from '../../store/store';
|
|
4
|
-
import { filterValidOverridableProps } from '../../utils/filter-valid-overridable-props';
|
|
5
|
-
import { deleteOverridableProp } from '../store/actions/delete-overridable-prop';
|
|
6
|
-
import { updateComponentSanitizedAttribute } from '../store/actions/update-component-sanitized-attribute';
|
|
7
|
-
|
|
8
|
-
export function SanitizeOverridableProps() {
|
|
9
|
-
const currentComponentId = useCurrentComponentId();
|
|
10
|
-
const overridableProps = useOverridableProps( currentComponentId );
|
|
11
|
-
const isSanitized = useIsSanitizedComponent( currentComponentId, 'overridableProps' );
|
|
12
|
-
|
|
13
|
-
useEffect( () => {
|
|
14
|
-
if ( isSanitized || ! overridableProps || ! currentComponentId ) {
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const filtered = filterValidOverridableProps( overridableProps );
|
|
19
|
-
|
|
20
|
-
const propsToDelete = Object.keys( overridableProps.props ?? {} ).filter( ( key ) => ! filtered.props[ key ] );
|
|
21
|
-
|
|
22
|
-
if ( propsToDelete.length > 0 ) {
|
|
23
|
-
propsToDelete.forEach( ( key ) => {
|
|
24
|
-
deleteOverridableProp( { componentId: currentComponentId, propKey: key, source: 'system' } );
|
|
25
|
-
} );
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
updateComponentSanitizedAttribute( currentComponentId, 'overridableProps' );
|
|
29
|
-
}, [ currentComponentId, isSanitized, overridableProps ] );
|
|
30
|
-
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { type V1Document } from '@elementor/editor-documents';
|
|
2
|
-
import { type V1Element } from '@elementor/editor-elements';
|
|
3
|
-
|
|
4
|
-
import { componentsSelectors } from '../../store/selectors';
|
|
5
|
-
import { COMPONENT_DOCUMENT_TYPE } from '../consts';
|
|
6
|
-
|
|
7
|
-
export const setComponentOverridablePropsSettingsBeforeSave = ( {
|
|
8
|
-
container,
|
|
9
|
-
}: {
|
|
10
|
-
container: V1Element & { document: V1Document };
|
|
11
|
-
} ) => {
|
|
12
|
-
const currentDocument = container.document;
|
|
13
|
-
|
|
14
|
-
if ( ! currentDocument || currentDocument.config.type !== COMPONENT_DOCUMENT_TYPE ) {
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const overridableProps = componentsSelectors.getOverridableProps( currentDocument.id );
|
|
19
|
-
if ( overridableProps ) {
|
|
20
|
-
container.settings.set( 'overridable_props', overridableProps );
|
|
21
|
-
}
|
|
22
|
-
};
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { type NotificationData, notify } from '@elementor/editor-notifications';
|
|
2
|
-
|
|
3
|
-
import { apiClient } from '../../api';
|
|
4
|
-
import { componentsSelectors } from '../../store/selectors';
|
|
5
|
-
import { type DocumentSaveStatus } from '../../types';
|
|
6
|
-
|
|
7
|
-
const failedNotification = ( message: string ): NotificationData => ( {
|
|
8
|
-
type: 'error',
|
|
9
|
-
message: `Failed to archive components: ${ message }`,
|
|
10
|
-
id: 'failed-archived-components-notification',
|
|
11
|
-
} );
|
|
12
|
-
|
|
13
|
-
export const updateArchivedComponentBeforeSave = async ( status: DocumentSaveStatus ) => {
|
|
14
|
-
try {
|
|
15
|
-
const archivedComponents = componentsSelectors.getArchivedThisSession();
|
|
16
|
-
|
|
17
|
-
if ( ! archivedComponents.length ) {
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const result = await apiClient.updateArchivedComponents( archivedComponents, status );
|
|
22
|
-
|
|
23
|
-
const failedIds = result.failedIds.join( ', ' );
|
|
24
|
-
|
|
25
|
-
if ( failedIds ) {
|
|
26
|
-
notify( failedNotification( failedIds ) );
|
|
27
|
-
}
|
|
28
|
-
} catch ( error ) {
|
|
29
|
-
throw new Error( `Failed to update archived components: ${ error }` );
|
|
30
|
-
}
|
|
31
|
-
};
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { apiClient } from '../../api';
|
|
2
|
-
import { componentsActions } from '../../store/dispatchers';
|
|
3
|
-
import { componentsSelectors } from '../../store/selectors';
|
|
4
|
-
import { type DocumentSaveStatus } from '../../types';
|
|
5
|
-
|
|
6
|
-
export const updateComponentTitleBeforeSave = async ( status: DocumentSaveStatus ) => {
|
|
7
|
-
const updatedComponentNames = componentsSelectors.getUpdatedComponentNames();
|
|
8
|
-
|
|
9
|
-
if ( ! updatedComponentNames.length ) {
|
|
10
|
-
return;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const result = await apiClient.updateComponentTitle( updatedComponentNames, status );
|
|
14
|
-
|
|
15
|
-
if ( result.failedIds.length === 0 ) {
|
|
16
|
-
componentsActions.cleanUpdatedComponentNames();
|
|
17
|
-
}
|
|
18
|
-
};
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { z } from '@elementor/schema';
|
|
2
|
-
import { __ } from '@wordpress/i18n';
|
|
3
|
-
|
|
4
|
-
export const MIN_NAME_LENGTH = 2;
|
|
5
|
-
const MAX_NAME_LENGTH = 50;
|
|
6
|
-
|
|
7
|
-
const baseComponentSchema = z
|
|
8
|
-
.string()
|
|
9
|
-
.trim()
|
|
10
|
-
.max( MAX_NAME_LENGTH, __( 'Component name is too long. Please keep it under 50 characters.', 'elementor' ) );
|
|
11
|
-
|
|
12
|
-
export const createBaseComponentSchema = ( existingNames: string[] ) => {
|
|
13
|
-
return z.object( {
|
|
14
|
-
componentName: baseComponentSchema.refine( ( value ) => ! existingNames.includes( value ), {
|
|
15
|
-
message: __( 'Component name already exists', 'elementor' ),
|
|
16
|
-
} ),
|
|
17
|
-
} );
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export const createSubmitComponentSchema = ( existingNames: string[] ) => {
|
|
21
|
-
const baseSchema = createBaseComponentSchema( existingNames );
|
|
22
|
-
|
|
23
|
-
return baseSchema.extend( {
|
|
24
|
-
componentName: baseSchema.shape.componentName
|
|
25
|
-
.refine( ( value ) => value.length > 0, {
|
|
26
|
-
message: __( 'Component name is required.', 'elementor' ),
|
|
27
|
-
} )
|
|
28
|
-
.refine( ( value ) => value.length >= MIN_NAME_LENGTH, {
|
|
29
|
-
message: __( 'Component name is too short. Please enter at least 2 characters.', 'elementor' ),
|
|
30
|
-
} ),
|
|
31
|
-
} );
|
|
32
|
-
};
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { componentsSelectors } from '../../store/selectors';
|
|
2
|
-
import { createSubmitComponentSchema } from './component-form-schema';
|
|
3
|
-
|
|
4
|
-
type ValidationResult = { isValid: true; errorMessage: null } | { isValid: false; errorMessage: string };
|
|
5
|
-
|
|
6
|
-
export function validateComponentName( label: string ): ValidationResult {
|
|
7
|
-
const existingComponentTitles = componentsSelectors.getComponents()?.map( ( { name } ) => name ) ?? [];
|
|
8
|
-
const schema = createSubmitComponentSchema( existingComponentTitles );
|
|
9
|
-
const result = schema.safeParse( { componentName: label.toLowerCase() } );
|
|
10
|
-
|
|
11
|
-
if ( result.success ) {
|
|
12
|
-
return {
|
|
13
|
-
isValid: true,
|
|
14
|
-
errorMessage: null,
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const formattedErrors = result.error.format();
|
|
19
|
-
const errorMessage = formattedErrors.componentName?._errors[ 0 ] ?? formattedErrors._errors[ 0 ];
|
|
20
|
-
|
|
21
|
-
return {
|
|
22
|
-
isValid: false,
|
|
23
|
-
errorMessage,
|
|
24
|
-
};
|
|
25
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { type V1ElementModelProps } from '@elementor/editor-elements';
|
|
2
|
-
|
|
3
|
-
export type ComponentInstanceParams = {
|
|
4
|
-
id?: number;
|
|
5
|
-
name: string;
|
|
6
|
-
uid: string;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export const createComponentModel = ( component: ComponentInstanceParams ): Omit< V1ElementModelProps, 'id' > => {
|
|
10
|
-
return {
|
|
11
|
-
elType: 'widget',
|
|
12
|
-
widgetType: 'e-component',
|
|
13
|
-
settings: {
|
|
14
|
-
component_instance: {
|
|
15
|
-
$$type: 'component-instance',
|
|
16
|
-
value: {
|
|
17
|
-
component_id: {
|
|
18
|
-
$$type: 'number',
|
|
19
|
-
value: component.id ?? component.uid,
|
|
20
|
-
},
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
editor_settings: {
|
|
25
|
-
component_uid: component.uid,
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
|
-
};
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getContainer,
|
|
3
|
-
getCurrentDocumentContainer,
|
|
4
|
-
getSelectedElements,
|
|
5
|
-
type V1Element,
|
|
6
|
-
} from '@elementor/editor-elements';
|
|
7
|
-
|
|
8
|
-
export const getContainerForNewElement = (): { container: V1Element | null; options?: { at: number } } => {
|
|
9
|
-
const currentDocumentContainer = getCurrentDocumentContainer();
|
|
10
|
-
const selectedElement = getSelectedElementContainer();
|
|
11
|
-
|
|
12
|
-
let container, options;
|
|
13
|
-
|
|
14
|
-
if ( selectedElement ) {
|
|
15
|
-
switch ( selectedElement.model.get( 'elType' ) ) {
|
|
16
|
-
case 'widget': {
|
|
17
|
-
container = selectedElement?.parent;
|
|
18
|
-
|
|
19
|
-
const selectedElIndex = selectedElement.view?._index ?? -1;
|
|
20
|
-
|
|
21
|
-
if ( selectedElIndex > -1 ) {
|
|
22
|
-
options = { at: selectedElIndex + 1 };
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
break;
|
|
26
|
-
}
|
|
27
|
-
case 'section': {
|
|
28
|
-
container = selectedElement?.children?.[ 0 ];
|
|
29
|
-
break;
|
|
30
|
-
}
|
|
31
|
-
default: {
|
|
32
|
-
container = selectedElement;
|
|
33
|
-
break;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return { container: container ?? currentDocumentContainer, options };
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
function getSelectedElementContainer() {
|
|
42
|
-
const selectedElements = getSelectedElements();
|
|
43
|
-
|
|
44
|
-
if ( selectedElements.length !== 1 ) {
|
|
45
|
-
return undefined;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return getContainer( selectedElements[ 0 ].id );
|
|
49
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { replaceElement, type V1ElementData } from '@elementor/editor-elements';
|
|
2
|
-
|
|
3
|
-
import { type ComponentInstanceParams, createComponentModel } from './create-component-model';
|
|
4
|
-
|
|
5
|
-
export const replaceElementWithComponent = ( element: V1ElementData, component: ComponentInstanceParams ) => {
|
|
6
|
-
return replaceElement( {
|
|
7
|
-
currentElementId: element.id,
|
|
8
|
-
newElement: createComponentModel( component ),
|
|
9
|
-
withHistory: false,
|
|
10
|
-
} );
|
|
11
|
-
};
|