@elementor/editor-components 4.0.0-manual → 4.0.0

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 (106) hide show
  1. package/dist/index.d.mts +1422 -1
  2. package/dist/index.d.ts +1422 -1
  3. package/dist/index.js +2096 -4814
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +2028 -4837
  6. package/dist/index.mjs.map +1 -1
  7. package/package.json +23 -23
  8. package/src/components/components-tab/components-list.tsx +92 -4
  9. package/src/components/components-tab/components-pro-notification.tsx +9 -15
  10. package/src/components/components-tab/components-update-notification.tsx +13 -0
  11. package/src/components/components-tab/components.tsx +52 -3
  12. package/src/components/components-tab/loading-components.tsx +26 -14
  13. package/src/components/components-update-alert.tsx +40 -0
  14. package/src/components/components-upgrade-alert.tsx +39 -0
  15. package/src/components/detach-instance-confirmation-dialog.tsx +50 -0
  16. package/src/components/instance-editing-panel/detach-action.tsx +76 -0
  17. package/src/components/instance-editing-panel/empty-state.tsx +9 -2
  18. package/src/components/instance-editing-panel/instance-editing-panel.tsx +34 -6
  19. package/src/components/instance-editing-panel/override-prop-control.tsx +14 -6
  20. package/src/components/instance-editing-panel/use-instance-panel-data.ts +2 -2
  21. package/src/components/instance-editing-panel/utils/correct-exposed-empty-override.ts +28 -0
  22. package/src/consts.ts +1 -0
  23. package/src/create-component-type.ts +130 -29
  24. package/src/index.ts +92 -0
  25. package/src/init.ts +6 -4
  26. package/src/store/actions/update-overridable-prop.ts +4 -10
  27. package/src/store/dispatchers.ts +63 -0
  28. package/src/store/extensible-slice.ts +168 -0
  29. package/src/store/selectors.ts +53 -0
  30. package/src/store/store-types.ts +48 -0
  31. package/src/store/store.ts +7 -169
  32. package/src/sync/publish-draft-components-in-page-before-save.ts +42 -1
  33. package/src/types.ts +1 -1
  34. package/src/utils/detach-component-instance/detach-component-instance.ts +172 -0
  35. package/src/utils/detach-component-instance/index.ts +1 -0
  36. package/src/utils/detach-component-instance/regenerate-local-style-ids.ts +53 -0
  37. package/src/utils/detach-component-instance/resolve-detached-instance.ts +94 -0
  38. package/src/utils/detach-component-instance/resolve-overridable-settings.ts +121 -0
  39. package/src/utils/is-component-instance.ts +1 -1
  40. package/src/utils/is-pro-components-supported.ts +11 -0
  41. package/src/utils/tracking.ts +2 -1
  42. package/src/extended/components/component-introduction.tsx +0 -77
  43. package/src/extended/components/component-panel-header/component-badge.tsx +0 -73
  44. package/src/extended/components/component-panel-header/component-panel-header.tsx +0 -98
  45. package/src/extended/components/component-properties-panel/component-properties-panel-content.tsx +0 -176
  46. package/src/extended/components/component-properties-panel/component-properties-panel.tsx +0 -43
  47. package/src/extended/components/component-properties-panel/properties-empty-state.tsx +0 -51
  48. package/src/extended/components/component-properties-panel/properties-group.tsx +0 -196
  49. package/src/extended/components/component-properties-panel/property-item.tsx +0 -124
  50. package/src/extended/components/component-properties-panel/sortable.tsx +0 -92
  51. package/src/extended/components/component-properties-panel/use-current-editable-item.ts +0 -73
  52. package/src/extended/components/component-properties-panel/utils/generate-unique-label.ts +0 -21
  53. package/src/extended/components/component-properties-panel/utils/validate-group-label.ts +0 -24
  54. package/src/extended/components/components-tab/component-item.tsx +0 -180
  55. package/src/extended/components/components-tab/components.tsx +0 -58
  56. package/src/extended/components/components-tab/delete-confirmation-dialog.tsx +0 -26
  57. package/src/extended/components/create-component-form/create-component-form.tsx +0 -282
  58. package/src/extended/components/create-component-form/hooks/use-form.ts +0 -72
  59. package/src/extended/components/create-component-form/utils/get-component-event-data.ts +0 -54
  60. package/src/extended/components/edit-component/component-modal.tsx +0 -133
  61. package/src/extended/components/edit-component/edit-component.tsx +0 -166
  62. package/src/extended/components/edit-component/use-canvas-document.ts +0 -9
  63. package/src/extended/components/edit-component/use-element-rect.ts +0 -81
  64. package/src/extended/components/instance-editing-panel/instance-editing-panel.tsx +0 -60
  65. package/src/extended/components/overridable-props/indicator.tsx +0 -83
  66. package/src/extended/components/overridable-props/overridable-prop-control.tsx +0 -127
  67. package/src/extended/components/overridable-props/overridable-prop-form.tsx +0 -135
  68. package/src/extended/components/overridable-props/overridable-prop-indicator.tsx +0 -138
  69. package/src/extended/components/overridable-props/utils/validate-prop-label.ts +0 -38
  70. package/src/extended/consts.ts +0 -3
  71. package/src/extended/hooks/use-navigate-back.ts +0 -24
  72. package/src/extended/init.ts +0 -104
  73. package/src/extended/mcp/index.ts +0 -14
  74. package/src/extended/mcp/save-as-component-tool.ts +0 -436
  75. package/src/extended/store/actions/add-overridable-group.ts +0 -59
  76. package/src/extended/store/actions/archive-component.ts +0 -19
  77. package/src/extended/store/actions/create-unpublished-component.ts +0 -102
  78. package/src/extended/store/actions/delete-overridable-group.ts +0 -38
  79. package/src/extended/store/actions/delete-overridable-prop.ts +0 -70
  80. package/src/extended/store/actions/rename-component.ts +0 -49
  81. package/src/extended/store/actions/rename-overridable-group.ts +0 -39
  82. package/src/extended/store/actions/reorder-group-props.ts +0 -43
  83. package/src/extended/store/actions/reorder-overridable-groups.ts +0 -30
  84. package/src/extended/store/actions/reset-sanitized-components.ts +0 -7
  85. package/src/extended/store/actions/set-overridable-prop.ts +0 -117
  86. package/src/extended/store/actions/update-component-sanitized-attribute.ts +0 -8
  87. package/src/extended/store/actions/update-current-component.ts +0 -21
  88. package/src/extended/store/actions/update-overridable-prop-params.ts +0 -58
  89. package/src/extended/store/utils/groups-transformers.ts +0 -187
  90. package/src/extended/sync/before-save.ts +0 -52
  91. package/src/extended/sync/cleanup-overridable-props-on-delete.ts +0 -85
  92. package/src/extended/sync/create-components-before-save.ts +0 -113
  93. package/src/extended/sync/handle-component-edit-mode-container.ts +0 -114
  94. package/src/extended/sync/prevent-non-atomic-nesting.ts +0 -198
  95. package/src/extended/sync/revert-overridables-on-copy-or-duplicate.ts +0 -66
  96. package/src/extended/sync/sanitize-overridable-props.ts +0 -32
  97. package/src/extended/sync/set-component-overridable-props-settings-before-save.ts +0 -23
  98. package/src/extended/sync/update-archived-component-before-save.ts +0 -32
  99. package/src/extended/sync/update-component-title-before-save.ts +0 -19
  100. package/src/extended/utils/component-form-schema.ts +0 -32
  101. package/src/extended/utils/component-name-validation.ts +0 -27
  102. package/src/extended/utils/create-component-model.ts +0 -28
  103. package/src/extended/utils/get-container-for-new-element.ts +0 -49
  104. package/src/extended/utils/is-editing-component.ts +0 -13
  105. package/src/extended/utils/replace-element-with-component.ts +0 -11
  106. package/src/extended/utils/revert-overridable-settings.ts +0 -207
@@ -1,70 +0,0 @@
1
- import { __dispatch as dispatch, __getState as getState } from '@elementor/store';
2
-
3
- import { selectCurrentComponent, selectOverridableProps, slice } from '../../../store/store';
4
- import { type ComponentId, type OverridableProp } from '../../../types';
5
- import { type Source, trackComponentEvent } from '../../../utils/tracking';
6
- import { revertElementOverridableSetting } from '../../utils/revert-overridable-settings';
7
- import { removePropFromAllGroups } from '../utils/groups-transformers';
8
-
9
- type DeletePropParams = {
10
- componentId: ComponentId;
11
- propKey: string | string[];
12
- source: Source;
13
- };
14
-
15
- export function deleteOverridableProp( { componentId, propKey, source }: DeletePropParams ): void {
16
- const overridableProps = selectOverridableProps( getState(), componentId );
17
-
18
- if ( ! overridableProps || Object.keys( overridableProps.props ).length === 0 ) {
19
- return;
20
- }
21
-
22
- const propKeysToDelete = Array.isArray( propKey ) ? propKey : [ propKey ];
23
- const deletedProps: OverridableProp[] = [];
24
-
25
- for ( const key of propKeysToDelete ) {
26
- const prop = overridableProps.props[ key ];
27
-
28
- if ( ! prop ) {
29
- continue;
30
- }
31
-
32
- deletedProps.push( prop );
33
- revertElementOverridableSetting( prop.elementId, prop.propKey, prop.originValue, key );
34
- }
35
-
36
- if ( deletedProps.length === 0 ) {
37
- return;
38
- }
39
-
40
- const remainingProps = Object.fromEntries(
41
- Object.entries( overridableProps.props ).filter( ( [ key ] ) => ! propKeysToDelete.includes( key ) )
42
- );
43
-
44
- const updatedGroups = removePropFromAllGroups( overridableProps.groups, propKey );
45
-
46
- dispatch(
47
- slice.actions.setOverridableProps( {
48
- componentId,
49
- overridableProps: {
50
- ...overridableProps,
51
- props: remainingProps,
52
- groups: updatedGroups,
53
- },
54
- } )
55
- );
56
-
57
- const currentComponent = selectCurrentComponent( getState() );
58
-
59
- for ( const prop of deletedProps ) {
60
- trackComponentEvent( {
61
- action: 'propertyRemoved',
62
- source,
63
- component_uid: currentComponent?.uid,
64
- property_id: prop.overrideKey,
65
- property_path: prop.propKey,
66
- property_name: prop.label,
67
- element_type: prop.widgetType ?? prop.elType,
68
- } );
69
- }
70
- }
@@ -1,49 +0,0 @@
1
- import { getV1DocumentsManager, setDocumentModifiedStatus } from '@elementor/editor-documents';
2
- import { getAllDescendants, type V1Element } from '@elementor/editor-elements';
3
- import { __dispatch as dispatch } from '@elementor/store';
4
-
5
- import { COMPONENT_WIDGET_TYPE } from '../../../create-component-type';
6
- import { slice } from '../../../store/store';
7
-
8
- const TITLE_EXTERNAL_CHANGE_COMMAND = 'title_external_change';
9
-
10
- export const renameComponent = ( componentUid: string, newName: string ) => {
11
- dispatch( slice.actions.rename( { componentUid, name: newName } ) );
12
-
13
- setDocumentModifiedStatus( true );
14
-
15
- refreshComponentInstanceTitles( componentUid );
16
- };
17
-
18
- function refreshComponentInstanceTitles( componentUid: string ) {
19
- const documentContainer = getDocumentContainer();
20
-
21
- if ( ! documentContainer ) {
22
- return;
23
- }
24
-
25
- const componentInstances = findComponentInstancesByUid( documentContainer, componentUid );
26
-
27
- componentInstances.forEach( ( element ) => {
28
- element.model.trigger?.( TITLE_EXTERNAL_CHANGE_COMMAND );
29
- } );
30
- }
31
-
32
- function getDocumentContainer(): V1Element | undefined {
33
- const documentsManager = getV1DocumentsManager();
34
-
35
- return documentsManager?.getCurrent()?.container as V1Element | undefined;
36
- }
37
-
38
- function findComponentInstancesByUid( documentContainer: V1Element, componentUid: string ): V1Element[] {
39
- const allDescendants = getAllDescendants( documentContainer );
40
-
41
- return allDescendants.filter( ( element ) => {
42
- const widgetType = element.model.get( 'widgetType' );
43
- const editorSettings = element.model.get( 'editor_settings' );
44
-
45
- const isMatch = widgetType === COMPONENT_WIDGET_TYPE && editorSettings?.component_uid === componentUid;
46
-
47
- return isMatch;
48
- } );
49
- }
@@ -1,39 +0,0 @@
1
- import { __dispatch as dispatch, __getState as getState } from '@elementor/store';
2
-
3
- import { selectOverridableProps, slice } from '../../../store/store';
4
- import { type ComponentId } from '../../../types';
5
- import { renameGroup } from '../utils/groups-transformers';
6
-
7
- type RenameGroupParams = {
8
- componentId: ComponentId;
9
- groupId: string;
10
- label: string;
11
- };
12
-
13
- export function renameOverridableGroup( { componentId, groupId, label }: RenameGroupParams ): boolean {
14
- const overridableProps = selectOverridableProps( getState(), componentId );
15
-
16
- if ( ! overridableProps ) {
17
- return false;
18
- }
19
-
20
- const group = overridableProps.groups.items[ groupId ];
21
-
22
- if ( ! group ) {
23
- return false;
24
- }
25
-
26
- const updatedGroups = renameGroup( overridableProps.groups, groupId, label );
27
-
28
- dispatch(
29
- slice.actions.setOverridableProps( {
30
- componentId,
31
- overridableProps: {
32
- ...overridableProps,
33
- groups: updatedGroups,
34
- },
35
- } )
36
- );
37
-
38
- return true;
39
- }
@@ -1,43 +0,0 @@
1
- import { __dispatch as dispatch, __getState as getState } from '@elementor/store';
2
-
3
- import { selectOverridableProps, slice } from '../../../store/store';
4
- import { type ComponentId } from '../../../types';
5
-
6
- type ReorderGroupPropsParams = {
7
- componentId: ComponentId;
8
- groupId: string;
9
- newPropsOrder: string[];
10
- };
11
-
12
- export function reorderGroupProps( { componentId, groupId, newPropsOrder }: ReorderGroupPropsParams ): void {
13
- const overridableProps = selectOverridableProps( getState(), componentId );
14
-
15
- if ( ! overridableProps ) {
16
- return;
17
- }
18
-
19
- const group = overridableProps.groups.items[ groupId ];
20
-
21
- if ( ! group ) {
22
- return;
23
- }
24
-
25
- dispatch(
26
- slice.actions.setOverridableProps( {
27
- componentId,
28
- overridableProps: {
29
- ...overridableProps,
30
- groups: {
31
- ...overridableProps.groups,
32
- items: {
33
- ...overridableProps.groups.items,
34
- [ groupId ]: {
35
- ...group,
36
- props: newPropsOrder,
37
- },
38
- },
39
- },
40
- },
41
- } )
42
- );
43
- }
@@ -1,30 +0,0 @@
1
- import { __dispatch as dispatch, __getState as getState } from '@elementor/store';
2
-
3
- import { selectOverridableProps, slice } from '../../../store/store';
4
- import { type ComponentId } from '../../../types';
5
-
6
- type ReorderGroupsParams = {
7
- componentId: ComponentId;
8
- newOrder: string[];
9
- };
10
-
11
- export function reorderOverridableGroups( { componentId, newOrder }: ReorderGroupsParams ): void {
12
- const overridableProps = selectOverridableProps( getState(), componentId );
13
-
14
- if ( ! overridableProps ) {
15
- return;
16
- }
17
-
18
- dispatch(
19
- slice.actions.setOverridableProps( {
20
- componentId,
21
- overridableProps: {
22
- ...overridableProps,
23
- groups: {
24
- ...overridableProps.groups,
25
- order: newOrder,
26
- },
27
- },
28
- } )
29
- );
30
- }
@@ -1,7 +0,0 @@
1
- import { __dispatch as dispatch } from '@elementor/store';
2
-
3
- import { slice } from '../../../store/store';
4
-
5
- export function resetSanitizedComponents() {
6
- dispatch( slice.actions.resetSanitizedComponents() );
7
- }
@@ -1,117 +0,0 @@
1
- import { type PropValue } from '@elementor/editor-props';
2
- import { __dispatch as dispatch, __getState as getState } from '@elementor/store';
3
- import { generateUniqueId } from '@elementor/utils';
4
-
5
- import { selectCurrentComponent, selectOverridableProps, slice } from '../../../store/store';
6
- import { type OriginPropFields, type OverridableProp } from '../../../types';
7
- import { type Source, trackComponentEvent } from '../../../utils/tracking';
8
- import {
9
- addPropToGroup,
10
- ensureGroupInOrder,
11
- removePropFromGroup,
12
- removePropsFromState,
13
- resolveOrCreateGroup,
14
- } from '../utils/groups-transformers';
15
-
16
- type Props = {
17
- componentId: number;
18
- overrideKey: string | null;
19
- elementId: string;
20
- label: string;
21
- groupId: string | null;
22
- propKey: string;
23
- elType: string;
24
- widgetType: string;
25
- originValue: PropValue;
26
- originPropFields?: OriginPropFields;
27
- source: Source;
28
- };
29
-
30
- export function setOverridableProp( {
31
- componentId,
32
- overrideKey,
33
- elementId,
34
- label,
35
- groupId,
36
- propKey,
37
- elType,
38
- widgetType,
39
- originValue,
40
- originPropFields,
41
- source,
42
- }: Props ): OverridableProp | undefined {
43
- const overridableProps = selectOverridableProps( getState(), componentId );
44
-
45
- if ( ! overridableProps ) {
46
- return;
47
- }
48
-
49
- const existingOverridableProp = overrideKey ? overridableProps.props[ overrideKey ] : null;
50
- const duplicatedTargetProps = Object.values( overridableProps.props ).filter(
51
- ( prop ) => prop.elementId === elementId && prop.propKey === propKey && prop !== existingOverridableProp
52
- );
53
-
54
- const { groups: groupsAfterResolve, groupId: currentGroupId } = resolveOrCreateGroup(
55
- overridableProps.groups,
56
- groupId || existingOverridableProp?.groupId || undefined
57
- );
58
-
59
- const overridableProp: OverridableProp = {
60
- overrideKey: existingOverridableProp?.overrideKey || generateUniqueId( 'prop' ),
61
- label,
62
- elementId,
63
- propKey,
64
- widgetType,
65
- elType,
66
- originValue,
67
- groupId: currentGroupId,
68
- originPropFields,
69
- };
70
-
71
- const stateAfterRemovingDuplicates = removePropsFromState(
72
- { ...overridableProps, groups: groupsAfterResolve },
73
- duplicatedTargetProps
74
- );
75
-
76
- const props = {
77
- ...stateAfterRemovingDuplicates.props,
78
- [ overridableProp.overrideKey ]: overridableProp,
79
- };
80
-
81
- let groups = addPropToGroup( stateAfterRemovingDuplicates.groups, currentGroupId, overridableProp.overrideKey );
82
- groups = ensureGroupInOrder( groups, currentGroupId );
83
-
84
- const isChangingGroups = existingOverridableProp && existingOverridableProp.groupId !== currentGroupId;
85
-
86
- if ( isChangingGroups ) {
87
- groups = removePropFromGroup( groups, existingOverridableProp.groupId, overridableProp.overrideKey );
88
- }
89
-
90
- dispatch(
91
- slice.actions.setOverridableProps( {
92
- componentId,
93
- overridableProps: {
94
- props,
95
- groups,
96
- },
97
- } )
98
- );
99
-
100
- const isNewProperty = ! existingOverridableProp;
101
-
102
- if ( isNewProperty ) {
103
- const currentComponent = selectCurrentComponent( getState() );
104
-
105
- trackComponentEvent( {
106
- action: 'propertyExposed',
107
- source,
108
- component_uid: currentComponent?.uid,
109
- property_id: overridableProp.overrideKey,
110
- property_path: propKey,
111
- property_name: label,
112
- element_type: widgetType ?? elType,
113
- } );
114
- }
115
-
116
- return overridableProp;
117
- }
@@ -1,8 +0,0 @@
1
- import { __dispatch as dispatch } from '@elementor/store';
2
-
3
- import { type SanitizeAttributes, slice } from '../../../store/store';
4
- import { type ComponentId } from '../../../types';
5
-
6
- export function updateComponentSanitizedAttribute( componentId: ComponentId, attribute: SanitizeAttributes ) {
7
- dispatch( slice.actions.updateComponentSanitizedAttribute( { componentId, attribute } ) );
8
- }
@@ -1,21 +0,0 @@
1
- import { type V1Document } from '@elementor/editor-documents';
2
- import { __getStore as getStore } from '@elementor/store';
3
-
4
- import { type ComponentsPathItem, slice } from '../../../store/store';
5
-
6
- export function updateCurrentComponent( {
7
- path,
8
- currentComponentId,
9
- }: {
10
- path: ComponentsPathItem[];
11
- currentComponentId: V1Document[ 'id' ] | null;
12
- } ) {
13
- const dispatch = getStore()?.dispatch;
14
-
15
- if ( ! dispatch ) {
16
- return;
17
- }
18
-
19
- dispatch( slice.actions.setPath( path ) );
20
- dispatch( slice.actions.setCurrentComponentId( currentComponentId ) );
21
- }
@@ -1,58 +0,0 @@
1
- import { __dispatch as dispatch, __getState as getState } from '@elementor/store';
2
-
3
- import { selectOverridableProps, slice } from '../../../store/store';
4
- import { type ComponentId, type OverridableProp } from '../../../types';
5
- import { movePropBetweenGroups } from '../utils/groups-transformers';
6
-
7
- type UpdatePropParams = {
8
- componentId: ComponentId;
9
- overrideKey: string;
10
- label: string;
11
- groupId: string | null;
12
- };
13
-
14
- export function updateOverridablePropParams( {
15
- componentId,
16
- overrideKey,
17
- label,
18
- groupId,
19
- }: UpdatePropParams ): OverridableProp | undefined {
20
- const overridableProps = selectOverridableProps( getState(), componentId );
21
-
22
- if ( ! overridableProps ) {
23
- return;
24
- }
25
-
26
- const prop = overridableProps.props[ overrideKey ];
27
-
28
- if ( ! prop ) {
29
- return;
30
- }
31
-
32
- const oldGroupId = prop.groupId;
33
- const newGroupId = groupId ?? oldGroupId;
34
-
35
- const updatedProp: OverridableProp = {
36
- ...prop,
37
- label,
38
- groupId: newGroupId,
39
- };
40
-
41
- const updatedGroups = movePropBetweenGroups( overridableProps.groups, overrideKey, oldGroupId, newGroupId );
42
-
43
- dispatch(
44
- slice.actions.setOverridableProps( {
45
- componentId,
46
- overridableProps: {
47
- ...overridableProps,
48
- props: {
49
- ...overridableProps.props,
50
- [ overrideKey ]: updatedProp,
51
- },
52
- groups: updatedGroups,
53
- },
54
- } )
55
- );
56
-
57
- return updatedProp;
58
- }
@@ -1,187 +0,0 @@
1
- import { generateUniqueId } from '@elementor/utils';
2
- import { __ } from '@wordpress/i18n';
3
-
4
- import { type OverridableProp, type OverridableProps, type OverridablePropsGroup } from '../../../types';
5
-
6
- type Groups = OverridableProps[ 'groups' ];
7
-
8
- export function removePropFromAllGroups( groups: Groups, propKey: string | string[] ): Groups {
9
- const propKeys = Array.isArray( propKey ) ? propKey : [ propKey ];
10
-
11
- return {
12
- ...groups,
13
- items: Object.fromEntries(
14
- Object.entries( groups.items ).map( ( [ groupId, group ] ) => [
15
- groupId,
16
- {
17
- ...group,
18
- props: group.props.filter( ( p ) => ! propKeys.includes( p ) ),
19
- },
20
- ] )
21
- ),
22
- };
23
- }
24
-
25
- export function addPropToGroup( groups: Groups, groupId: string, propKey: string ): Groups {
26
- const group = groups.items[ groupId ];
27
-
28
- if ( ! group ) {
29
- return groups;
30
- }
31
-
32
- if ( group.props.includes( propKey ) ) {
33
- return groups;
34
- }
35
-
36
- return {
37
- ...groups,
38
- items: {
39
- ...groups.items,
40
- [ groupId ]: {
41
- ...group,
42
- props: [ ...group.props, propKey ],
43
- },
44
- },
45
- };
46
- }
47
-
48
- export function movePropBetweenGroups(
49
- groups: Groups,
50
- propKey: string,
51
- fromGroupId: string,
52
- toGroupId: string
53
- ): Groups {
54
- if ( fromGroupId === toGroupId ) {
55
- return groups;
56
- }
57
-
58
- const withoutProp = removePropFromGroup( groups, fromGroupId, propKey );
59
- return addPropToGroup( withoutProp, toGroupId, propKey );
60
- }
61
-
62
- export function removePropFromGroup( groups: Groups, groupId: string, propKey: string ): Groups {
63
- const group = groups.items[ groupId ];
64
-
65
- if ( ! group ) {
66
- return groups;
67
- }
68
-
69
- return {
70
- ...groups,
71
- items: {
72
- ...groups.items,
73
- [ groupId ]: {
74
- ...group,
75
- props: group.props.filter( ( p ) => p !== propKey ),
76
- },
77
- },
78
- };
79
- }
80
-
81
- type ResolvedGroup = {
82
- groups: Groups;
83
- groupId: string;
84
- };
85
-
86
- export function resolveOrCreateGroup( groups: Groups, requestedGroupId?: string ): ResolvedGroup {
87
- if ( requestedGroupId && groups.items[ requestedGroupId ] ) {
88
- return { groups, groupId: requestedGroupId };
89
- }
90
-
91
- if ( ! requestedGroupId && groups.order.length > 0 ) {
92
- return { groups, groupId: groups.order[ 0 ] };
93
- }
94
-
95
- return createGroup( groups, requestedGroupId );
96
- }
97
-
98
- function createGroup( groups: Groups, groupId?: string, label?: string ): ResolvedGroup {
99
- const newGroupId = groupId || generateUniqueId( 'group' );
100
- const newLabel = label || __( 'Default', 'elementor' );
101
-
102
- return {
103
- groups: {
104
- ...groups,
105
- items: {
106
- ...groups.items,
107
- [ newGroupId ]: {
108
- id: newGroupId,
109
- label: newLabel,
110
- props: [],
111
- },
112
- },
113
- order: [ ...groups.order, newGroupId ],
114
- },
115
- groupId: newGroupId,
116
- };
117
- }
118
-
119
- export function removePropsFromState(
120
- overridableProps: OverridableProps,
121
- propsToRemove: OverridableProp[]
122
- ): OverridableProps {
123
- const overrideKeysToRemove = propsToRemove.map( ( prop ) => prop.overrideKey );
124
-
125
- const remainingProps = Object.fromEntries(
126
- Object.entries( overridableProps.props ).filter( ( [ , prop ] ) => ! propsToRemove.includes( prop ) )
127
- );
128
-
129
- const updatedGroupItems = Object.fromEntries(
130
- Object.entries( overridableProps.groups.items ).map(
131
- ( [ groupId, group ]: [ string, OverridablePropsGroup ] ) => [
132
- groupId,
133
- {
134
- ...group,
135
- props: group.props.filter( ( prop ) => ! overrideKeysToRemove.includes( prop ) ),
136
- },
137
- ]
138
- )
139
- );
140
-
141
- return {
142
- props: remainingProps,
143
- groups: {
144
- items: updatedGroupItems,
145
- order: overridableProps.groups.order.filter( ( groupId ) => ! overrideKeysToRemove.includes( groupId ) ),
146
- },
147
- };
148
- }
149
-
150
- export function ensureGroupInOrder( groups: Groups, groupId: string ): Groups {
151
- if ( groups.order.includes( groupId ) ) {
152
- return groups;
153
- }
154
-
155
- return {
156
- ...groups,
157
- order: [ ...groups.order, groupId ],
158
- };
159
- }
160
-
161
- export function deleteGroup( groups: Groups, groupId: string ): Groups {
162
- const { [ groupId ]: removed, ...remainingItems } = groups.items;
163
-
164
- return {
165
- items: remainingItems,
166
- order: groups.order.filter( ( id ) => id !== groupId ),
167
- };
168
- }
169
-
170
- export function renameGroup( groups: Groups, groupId: string, newLabel: string ): Groups {
171
- const group = groups.items[ groupId ];
172
-
173
- if ( ! group ) {
174
- return groups;
175
- }
176
-
177
- return {
178
- ...groups,
179
- items: {
180
- ...groups.items,
181
- [ groupId ]: {
182
- ...group,
183
- label: newLabel,
184
- },
185
- },
186
- };
187
- }
@@ -1,52 +0,0 @@
1
- import { type V1Document } from '@elementor/editor-documents';
2
- import { type V1Element, type V1ElementData } from '@elementor/editor-elements';
3
-
4
- import { publishDraftComponentsInPageBeforeSave } from '../../sync/publish-draft-components-in-page-before-save';
5
- import { type DocumentSaveStatus } from '../../types';
6
- import { setComponentOverridablePropsSettingsBeforeSave } from '../sync/set-component-overridable-props-settings-before-save';
7
- import { updateArchivedComponentBeforeSave } from '../sync/update-archived-component-before-save';
8
- import { updateComponentTitleBeforeSave } from '../sync/update-component-title-before-save';
9
- import { createComponentsBeforeSave } from './create-components-before-save';
10
-
11
- type Options = {
12
- container: V1Element & {
13
- document: V1Document;
14
- model: {
15
- get: ( key: 'elements' ) => {
16
- toJSON: () => V1ElementData[];
17
- };
18
- };
19
- };
20
- status: DocumentSaveStatus;
21
- };
22
-
23
- export const beforeSave = ( { container, status }: Options ) => {
24
- const elements = container?.model.get( 'elements' ).toJSON?.() ?? [];
25
-
26
- return Promise.all( [
27
- syncComponents( { elements, status } ),
28
- setComponentOverridablePropsSettingsBeforeSave( { container } ),
29
- ] );
30
- };
31
-
32
- // These operations run sequentially to prevent race conditions when multiple
33
- // edits occur on the same component simultaneously.
34
- // TODO: Consolidate these into a single PUT /components endpoint.
35
- const syncComponents = async ( { elements, status }: { elements: V1ElementData[]; status: DocumentSaveStatus } ) => {
36
- // This order is important - first update existing components, then create new components,
37
- // Since new component validation depends on the existing components (preventing duplicate names).
38
- await updateExistingComponentsBeforeSave( { elements, status } );
39
- await createComponentsBeforeSave( { elements, status } );
40
- };
41
-
42
- const updateExistingComponentsBeforeSave = async ( {
43
- elements,
44
- status,
45
- }: {
46
- elements: V1ElementData[];
47
- status: DocumentSaveStatus;
48
- } ) => {
49
- await updateComponentTitleBeforeSave( status );
50
- await updateArchivedComponentBeforeSave( status );
51
- await publishDraftComponentsInPageBeforeSave( { elements, status } );
52
- };