@elementor/editor-components 4.1.0-741 → 4.1.0-742
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 +278 -213
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +250 -185
- package/dist/index.mjs.map +1 -1
- package/package.json +23 -23
- package/src/components/instance-editing-panel/override-prop-control.tsx +96 -33
- package/src/components/instance-editing-panel/utils/resolve-element-settings.ts +65 -0
- package/src/utils/filter-valid-overridable-props.ts +6 -61
- package/src/utils/overridable-props-utils.ts +0 -34
- package/src/utils/resolve-overrides-chain.ts +197 -0
- package/src/components/instance-editing-panel/use-resolved-origin-value.tsx +0 -119
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-components",
|
|
3
3
|
"description": "Elementor editor components",
|
|
4
|
-
"version": "4.1.0-
|
|
4
|
+
"version": "4.1.0-742",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "Elementor Team",
|
|
7
7
|
"homepage": "https://elementor.com/",
|
|
@@ -40,31 +40,31 @@
|
|
|
40
40
|
"dev": "tsup --config=../../tsup.dev.ts"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@elementor/editor": "4.1.0-
|
|
44
|
-
"@elementor/editor-canvas": "4.1.0-
|
|
45
|
-
"@elementor/editor-controls": "4.1.0-
|
|
46
|
-
"@elementor/editor-documents": "4.1.0-
|
|
47
|
-
"@elementor/editor-editing-panel": "4.1.0-
|
|
48
|
-
"@elementor/editor-elements": "4.1.0-
|
|
49
|
-
"@elementor/editor-elements-panel": "4.1.0-
|
|
50
|
-
"@elementor/editor-mcp": "4.1.0-
|
|
51
|
-
"@elementor/editor-templates": "4.1.0-
|
|
52
|
-
"@elementor/editor-panels": "4.1.0-
|
|
53
|
-
"@elementor/editor-props": "4.1.0-
|
|
54
|
-
"@elementor/editor-styles-repository": "4.1.0-
|
|
55
|
-
"@elementor/editor-ui": "4.1.0-
|
|
56
|
-
"@elementor/editor-v1-adapters": "4.1.0-
|
|
57
|
-
"@elementor/http-client": "4.1.0-
|
|
43
|
+
"@elementor/editor": "4.1.0-742",
|
|
44
|
+
"@elementor/editor-canvas": "4.1.0-742",
|
|
45
|
+
"@elementor/editor-controls": "4.1.0-742",
|
|
46
|
+
"@elementor/editor-documents": "4.1.0-742",
|
|
47
|
+
"@elementor/editor-editing-panel": "4.1.0-742",
|
|
48
|
+
"@elementor/editor-elements": "4.1.0-742",
|
|
49
|
+
"@elementor/editor-elements-panel": "4.1.0-742",
|
|
50
|
+
"@elementor/editor-mcp": "4.1.0-742",
|
|
51
|
+
"@elementor/editor-templates": "4.1.0-742",
|
|
52
|
+
"@elementor/editor-panels": "4.1.0-742",
|
|
53
|
+
"@elementor/editor-props": "4.1.0-742",
|
|
54
|
+
"@elementor/editor-styles-repository": "4.1.0-742",
|
|
55
|
+
"@elementor/editor-ui": "4.1.0-742",
|
|
56
|
+
"@elementor/editor-v1-adapters": "4.1.0-742",
|
|
57
|
+
"@elementor/http-client": "4.1.0-742",
|
|
58
58
|
"@elementor/icons": "^1.68.0",
|
|
59
|
-
"@elementor/events": "4.1.0-
|
|
60
|
-
"@elementor/query": "4.1.0-
|
|
61
|
-
"@elementor/schema": "4.1.0-
|
|
62
|
-
"@elementor/store": "4.1.0-
|
|
59
|
+
"@elementor/events": "4.1.0-742",
|
|
60
|
+
"@elementor/query": "4.1.0-742",
|
|
61
|
+
"@elementor/schema": "4.1.0-742",
|
|
62
|
+
"@elementor/store": "4.1.0-742",
|
|
63
63
|
"@elementor/ui": "1.36.17",
|
|
64
|
-
"@elementor/utils": "4.1.0-
|
|
64
|
+
"@elementor/utils": "4.1.0-742",
|
|
65
65
|
"@wordpress/i18n": "^5.13.0",
|
|
66
|
-
"@elementor/editor-notifications": "4.1.0-
|
|
67
|
-
"@elementor/editor-current-user": "4.1.0-
|
|
66
|
+
"@elementor/editor-notifications": "4.1.0-742",
|
|
67
|
+
"@elementor/editor-current-user": "4.1.0-742"
|
|
68
68
|
},
|
|
69
69
|
"peerDependencies": {
|
|
70
70
|
"react": "^18.3.1",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { useMemo } from 'react';
|
|
2
3
|
import {
|
|
3
4
|
ControlReplacementsProvider,
|
|
4
5
|
getControlReplacements,
|
|
@@ -29,6 +30,7 @@ import {
|
|
|
29
30
|
import {
|
|
30
31
|
type ComponentInstanceOverride,
|
|
31
32
|
componentInstanceOverridesPropTypeUtil,
|
|
33
|
+
type ComponentInstanceOverridesPropValue,
|
|
32
34
|
} from '../../prop-types/component-instance-overrides-prop-type';
|
|
33
35
|
import { componentInstancePropTypeUtil } from '../../prop-types/component-instance-prop-type';
|
|
34
36
|
import {
|
|
@@ -44,14 +46,18 @@ import { OverridablePropProvider } from '../../provider/overridable-prop-context
|
|
|
44
46
|
import { updateOverridableProp } from '../../store/actions/update-overridable-prop';
|
|
45
47
|
import { useCurrentComponentId } from '../../store/store';
|
|
46
48
|
import { type OriginPropFields, type OverridableProp, type OverridableProps } from '../../types';
|
|
47
|
-
import { getContainerByOriginId } from '../../utils/get-container-by-origin-id';
|
|
48
49
|
import { getPropTypeForComponentOverride } from '../../utils/get-prop-type-for-component-override';
|
|
49
50
|
import { getMatchingOverride } from '../../utils/overridable-props-utils';
|
|
50
51
|
import { resolveOverridePropValue } from '../../utils/resolve-override-prop-value';
|
|
52
|
+
import { resolveOverridesChain } from '../../utils/resolve-overrides-chain';
|
|
51
53
|
import { ControlLabel } from '../control-label';
|
|
52
54
|
import { OverrideControlInnerElementNotFoundError } from '../errors';
|
|
53
|
-
import { useResolvedOriginValue } from './use-resolved-origin-value';
|
|
54
55
|
import { correctExposedEmptyOverride } from './utils/correct-exposed-empty-override';
|
|
56
|
+
import {
|
|
57
|
+
applyOverridesToSettings,
|
|
58
|
+
type OverridesMapping,
|
|
59
|
+
unwrapOverridableSettings,
|
|
60
|
+
} from './utils/resolve-element-settings';
|
|
55
61
|
|
|
56
62
|
type Props = {
|
|
57
63
|
overrideKey: string;
|
|
@@ -92,8 +98,6 @@ function OverrideControl( { overridableProp }: InternalProps ) {
|
|
|
92
98
|
|
|
93
99
|
const matchingOverride = getMatchingOverride( overrides, overridableProp.overrideKey );
|
|
94
100
|
|
|
95
|
-
const recursiveOriginValue = useResolvedOriginValue( matchingOverride, overridableProp );
|
|
96
|
-
|
|
97
101
|
if ( ! componentId ) {
|
|
98
102
|
throw new Error( 'Component ID is required' );
|
|
99
103
|
}
|
|
@@ -102,14 +106,59 @@ function OverrideControl( { overridableProp }: InternalProps ) {
|
|
|
102
106
|
throw new Error( 'Component has no overridable props' );
|
|
103
107
|
}
|
|
104
108
|
|
|
109
|
+
const {
|
|
110
|
+
elementId: originElementId,
|
|
111
|
+
widgetType,
|
|
112
|
+
elType,
|
|
113
|
+
propKey,
|
|
114
|
+
} = overridableProp.originPropFields ?? overridableProp;
|
|
115
|
+
const type = elType === 'widget' ? widgetType : elType;
|
|
116
|
+
const elementType = getElementType( type );
|
|
117
|
+
|
|
118
|
+
const { elementId, overridesMapping } = useMemo( () => {
|
|
119
|
+
const overridesChainResult = resolveOverridesChain( {
|
|
120
|
+
outerOverridableProp: overridableProp,
|
|
121
|
+
outerInstanceId: componentInstanceElement.element.id,
|
|
122
|
+
} );
|
|
123
|
+
|
|
124
|
+
if ( overridesChainResult.isChainBroken ) {
|
|
125
|
+
throw new OverrideControlInnerElementNotFoundError( {
|
|
126
|
+
context: { componentId, elementId: originElementId },
|
|
127
|
+
} );
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
elementId: overridesChainResult.innerElement.id,
|
|
132
|
+
overridesMapping: overridesChainResult.overridesMapping,
|
|
133
|
+
};
|
|
134
|
+
}, [ overridableProp, componentInstanceElement.element.id, componentId, originElementId ] );
|
|
135
|
+
|
|
136
|
+
// Not reactive to inner element store changes — intentional.
|
|
137
|
+
// Inner element settings can only change in component edit mode, which unmounts this component.
|
|
138
|
+
const settingsWithInnerOverrides = useMemo( () => {
|
|
139
|
+
const settings = getElementSettings< AnyTransformable >(
|
|
140
|
+
elementId,
|
|
141
|
+
Object.keys( elementType?.propsSchema ?? {} )
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
return applyOverridesToSettings( settings, overridesMapping );
|
|
145
|
+
}, [ elementId, elementType?.propsSchema, overridesMapping ] );
|
|
146
|
+
|
|
147
|
+
const resolvedElementSettings = useMemo( () => {
|
|
148
|
+
const withAllOverrides = applyOverridesToSettings(
|
|
149
|
+
settingsWithInnerOverrides,
|
|
150
|
+
formatOverridesToApply( overrides )
|
|
151
|
+
);
|
|
152
|
+
return unwrapOverridableSettings( withAllOverrides );
|
|
153
|
+
}, [ settingsWithInnerOverrides, overrides ] );
|
|
154
|
+
|
|
105
155
|
const propType = getPropTypeForComponentOverride( overridableProp );
|
|
106
156
|
|
|
107
|
-
if ( ! propType ) {
|
|
157
|
+
if ( ! propType || ! elementType ) {
|
|
108
158
|
return null;
|
|
109
159
|
}
|
|
110
160
|
|
|
111
|
-
const
|
|
112
|
-
const propValue = resolvedOverrideValue ?? recursiveOriginValue ?? overridableProp.originValue;
|
|
161
|
+
const propValue = resolvedElementSettings[ propKey ];
|
|
113
162
|
|
|
114
163
|
const value = {
|
|
115
164
|
[ overridableProp.overrideKey ]: propValue,
|
|
@@ -161,8 +210,13 @@ function OverrideControl( { overridableProp }: InternalProps ) {
|
|
|
161
210
|
return;
|
|
162
211
|
}
|
|
163
212
|
|
|
164
|
-
const
|
|
165
|
-
|
|
213
|
+
const originPropFields = {
|
|
214
|
+
elType: overridableProp.elType,
|
|
215
|
+
widgetType: overridableProp.widgetType,
|
|
216
|
+
propKey: overridableProp.propKey,
|
|
217
|
+
elementId: overridableProp.elementId,
|
|
218
|
+
};
|
|
219
|
+
updateOverridableProp( wrappingComponentId, overridableValue, originPropFields );
|
|
166
220
|
}
|
|
167
221
|
};
|
|
168
222
|
|
|
@@ -172,29 +226,6 @@ function OverrideControl( { overridableProp }: InternalProps ) {
|
|
|
172
226
|
overridableProp.label
|
|
173
227
|
);
|
|
174
228
|
|
|
175
|
-
const {
|
|
176
|
-
elementId: originElementId,
|
|
177
|
-
widgetType,
|
|
178
|
-
elType,
|
|
179
|
-
propKey,
|
|
180
|
-
} = overridableProp.originPropFields ?? overridableProp;
|
|
181
|
-
|
|
182
|
-
const element = getContainerByOriginId( originElementId, componentInstanceElement.element.id );
|
|
183
|
-
|
|
184
|
-
if ( ! element ) {
|
|
185
|
-
throw new OverrideControlInnerElementNotFoundError( { context: { componentId, elementId: originElementId } } );
|
|
186
|
-
}
|
|
187
|
-
const elementId = element.id;
|
|
188
|
-
|
|
189
|
-
const type = elType === 'widget' ? widgetType : elType;
|
|
190
|
-
const elementType = getElementType( type );
|
|
191
|
-
|
|
192
|
-
if ( ! elementType ) {
|
|
193
|
-
return null;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const settings = getElementSettings< AnyTransformable >( elementId, Object.keys( elementType.propsSchema ) );
|
|
197
|
-
|
|
198
229
|
const propTypeSchema = createTopLevelObjectType( {
|
|
199
230
|
schema: {
|
|
200
231
|
[ overridableProp.overrideKey ]: propType,
|
|
@@ -206,7 +237,11 @@ function OverrideControl( { overridableProp }: InternalProps ) {
|
|
|
206
237
|
value={ componentOverridablePropTypeUtil.extract( matchingOverride ) ?? undefined }
|
|
207
238
|
componentInstanceElement={ componentInstanceElement }
|
|
208
239
|
>
|
|
209
|
-
<ElementProvider
|
|
240
|
+
<ElementProvider
|
|
241
|
+
element={ { id: elementId, type } }
|
|
242
|
+
elementType={ elementType }
|
|
243
|
+
settings={ resolvedElementSettings }
|
|
244
|
+
>
|
|
210
245
|
<SettingsField bind={ propKey } propDisplayName={ overridableProp.label }>
|
|
211
246
|
<PropProvider
|
|
212
247
|
propType={ propTypeSchema }
|
|
@@ -344,3 +379,31 @@ function isValidOverride( overridableProps: OverridableProps, override: Componen
|
|
|
344
379
|
|
|
345
380
|
return !! overridableProps.props[ overridableKey ];
|
|
346
381
|
}
|
|
382
|
+
|
|
383
|
+
function formatOverridesToApply( overrides: ComponentInstanceOverridesPropValue ): OverridesMapping {
|
|
384
|
+
if ( ! overrides ) {
|
|
385
|
+
return {};
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const result: OverridesMapping = {};
|
|
389
|
+
|
|
390
|
+
for ( const item of overrides ) {
|
|
391
|
+
const overridable = componentOverridablePropTypeUtil.extract( item );
|
|
392
|
+
let override: PropValue = item;
|
|
393
|
+
|
|
394
|
+
if ( overridable ) {
|
|
395
|
+
override = overridable.origin_value;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const extractedOverride = componentInstanceOverridePropTypeUtil.extract( override );
|
|
399
|
+
if ( ! extractedOverride ) {
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
result[ extractedOverride.override_key ] = {
|
|
404
|
+
value: extractedOverride.override_value as AnyTransformable | null,
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
return result;
|
|
409
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { type AnyTransformable } from '@elementor/editor-props';
|
|
2
|
+
|
|
3
|
+
import { componentOverridablePropTypeUtil } from '../../../prop-types/component-overridable-prop-type';
|
|
4
|
+
|
|
5
|
+
type ElementSettings = Record< string, AnyTransformable | null >;
|
|
6
|
+
|
|
7
|
+
export type OverridesMapping = {
|
|
8
|
+
[ key: string ]: {
|
|
9
|
+
value: AnyTransformable | null;
|
|
10
|
+
outermostKey?: string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export function applyOverridesToSettings(
|
|
15
|
+
elementSettings: ElementSettings,
|
|
16
|
+
overrides: OverridesMapping
|
|
17
|
+
): ElementSettings {
|
|
18
|
+
const result: ElementSettings = {};
|
|
19
|
+
|
|
20
|
+
for ( const [ propKey, propValue ] of Object.entries( elementSettings ) ) {
|
|
21
|
+
const overridable = componentOverridablePropTypeUtil.extract( propValue );
|
|
22
|
+
|
|
23
|
+
if ( ! overridable ) {
|
|
24
|
+
result[ propKey ] = propValue;
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const override = overrides[ overridable.override_key ];
|
|
29
|
+
|
|
30
|
+
if ( ! override ) {
|
|
31
|
+
result[ propKey ] = propValue;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if ( override.outermostKey && override.outermostKey !== overridable.override_key ) {
|
|
36
|
+
const originValue = overridable.origin_value as AnyTransformable | null;
|
|
37
|
+
|
|
38
|
+
result[ propKey ] = componentOverridablePropTypeUtil.create( {
|
|
39
|
+
override_key: override.outermostKey,
|
|
40
|
+
origin_value: override.value ?? originValue,
|
|
41
|
+
} );
|
|
42
|
+
} else {
|
|
43
|
+
result[ propKey ] = override.value ?? propValue;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function unwrapOverridableSettings( elementSettings: ElementSettings ): ElementSettings {
|
|
51
|
+
const result: ElementSettings = {};
|
|
52
|
+
|
|
53
|
+
for ( const [ propKey, propValue ] of Object.entries( elementSettings ) ) {
|
|
54
|
+
const overridable = componentOverridablePropTypeUtil.extract( propValue );
|
|
55
|
+
|
|
56
|
+
if ( ! overridable ) {
|
|
57
|
+
result[ propKey ] = propValue;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
result[ propKey ] = overridable.origin_value as AnyTransformable | null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
import { type ComponentInstanceOverride } from '../prop-types/component-instance-overrides-prop-type';
|
|
2
|
-
import { componentInstanceOverridesPropTypeUtil } from '../prop-types/component-instance-overrides-prop-type';
|
|
3
|
-
import { componentInstancePropTypeUtil } from '../prop-types/component-instance-prop-type';
|
|
4
|
-
import { componentOverridablePropTypeUtil } from '../prop-types/component-overridable-prop-type';
|
|
5
1
|
import { type OverridableProp, type OverridableProps } from '../types';
|
|
6
|
-
import {
|
|
7
|
-
import { getOverridableProp } from './get-overridable-prop';
|
|
8
|
-
import { extractInnerOverrideInfo } from './overridable-props-utils';
|
|
2
|
+
import { resolveOverridesChain } from './resolve-overrides-chain';
|
|
9
3
|
|
|
10
4
|
export function filterValidOverridableProps(
|
|
11
5
|
overridableProps: OverridableProps,
|
|
@@ -36,59 +30,10 @@ export function filterValidOverridableProps(
|
|
|
36
30
|
}
|
|
37
31
|
|
|
38
32
|
export function isExposedPropValid( prop: OverridableProp, instanceElementId?: string ): boolean {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const innerComponentInstanceElement = getContainerByOriginId( prop.elementId, instanceElementId );
|
|
45
|
-
|
|
46
|
-
if ( ! innerComponentInstanceElement ) {
|
|
47
|
-
return false;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const setting = innerComponentInstanceElement.settings?.get( 'component_instance' ) ?? null;
|
|
51
|
-
const componentInstance = componentInstancePropTypeUtil.extract( setting );
|
|
52
|
-
|
|
53
|
-
if ( ! componentInstance?.component_id?.value ) {
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const overrides = componentInstanceOverridesPropTypeUtil.extract( componentInstance.overrides ) ?? undefined;
|
|
58
|
-
const matchingOverride = findOverrideByOuterKey( overrides, prop.overrideKey );
|
|
59
|
-
const innerOverrideInfo = extractInnerOverrideInfo( matchingOverride );
|
|
60
|
-
|
|
61
|
-
if ( ! innerOverrideInfo ) {
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const { componentId, innerOverrideKey } = innerOverrideInfo;
|
|
66
|
-
const innerOverridableProp = getOverridableProp( { componentId, overrideKey: innerOverrideKey } );
|
|
67
|
-
|
|
68
|
-
if ( ! innerOverridableProp ) {
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return isExposedPropValid( innerOverridableProp, innerComponentInstanceElement.id );
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function findOverrideByOuterKey(
|
|
76
|
-
overrides: ComponentInstanceOverride[] | undefined,
|
|
77
|
-
outerKey: string
|
|
78
|
-
): ComponentInstanceOverride | null {
|
|
79
|
-
if ( ! overrides ) {
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return (
|
|
84
|
-
overrides.find( ( override ) => {
|
|
85
|
-
const overridableValue = componentOverridablePropTypeUtil.extract( override );
|
|
86
|
-
|
|
87
|
-
if ( overridableValue ) {
|
|
88
|
-
return overridableValue.override_key === outerKey;
|
|
89
|
-
}
|
|
33
|
+
const { isChainBroken } = resolveOverridesChain( {
|
|
34
|
+
outerOverridableProp: prop,
|
|
35
|
+
outerInstanceId: instanceElementId,
|
|
36
|
+
} );
|
|
90
37
|
|
|
91
|
-
|
|
92
|
-
} ) ?? null
|
|
93
|
-
);
|
|
38
|
+
return ! isChainBroken;
|
|
94
39
|
}
|
|
@@ -5,12 +5,6 @@ import {
|
|
|
5
5
|
} from '../prop-types/component-instance-overrides-prop-type';
|
|
6
6
|
import { componentOverridablePropTypeUtil } from '../prop-types/component-overridable-prop-type';
|
|
7
7
|
|
|
8
|
-
export type InnerOverrideInfo = {
|
|
9
|
-
componentId: number;
|
|
10
|
-
innerOverrideKey: string;
|
|
11
|
-
overrideValue: unknown;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
8
|
export function getMatchingOverride(
|
|
15
9
|
overrides: ComponentInstanceOverridesPropValue,
|
|
16
10
|
overrideKey: string
|
|
@@ -28,31 +22,3 @@ export function getMatchingOverride(
|
|
|
28
22
|
} ) ?? null
|
|
29
23
|
);
|
|
30
24
|
}
|
|
31
|
-
|
|
32
|
-
export function extractInnerOverrideInfo( override: ComponentInstanceOverride | null ): InnerOverrideInfo | null {
|
|
33
|
-
if ( ! override ) {
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const overridableValue = componentOverridablePropTypeUtil.extract( override );
|
|
38
|
-
const innerOverride = overridableValue
|
|
39
|
-
? componentInstanceOverridePropTypeUtil.extract( overridableValue.origin_value )
|
|
40
|
-
: componentInstanceOverridePropTypeUtil.extract( override );
|
|
41
|
-
|
|
42
|
-
if ( ! innerOverride ) {
|
|
43
|
-
return null;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const {
|
|
47
|
-
schema_source: schemaSource,
|
|
48
|
-
override_key: innerOverrideKey,
|
|
49
|
-
override_value: overrideValue,
|
|
50
|
-
} = innerOverride;
|
|
51
|
-
const componentId = schemaSource?.id;
|
|
52
|
-
|
|
53
|
-
if ( ! componentId || ! innerOverrideKey ) {
|
|
54
|
-
return null;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return { componentId, innerOverrideKey, overrideValue };
|
|
58
|
-
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { type V1Element } from '@elementor/editor-elements';
|
|
2
|
+
import { type AnyTransformable } from '@elementor/editor-props';
|
|
3
|
+
|
|
4
|
+
import { type OverridesMapping } from '../components/instance-editing-panel/utils/resolve-element-settings';
|
|
5
|
+
import {
|
|
6
|
+
type ComponentInstanceOverrideProp,
|
|
7
|
+
componentInstanceOverridePropTypeUtil,
|
|
8
|
+
} from '../prop-types/component-instance-override-prop-type';
|
|
9
|
+
import {
|
|
10
|
+
type ComponentInstanceOverride,
|
|
11
|
+
componentInstanceOverridesPropTypeUtil,
|
|
12
|
+
} from '../prop-types/component-instance-overrides-prop-type';
|
|
13
|
+
import { componentInstancePropTypeUtil } from '../prop-types/component-instance-prop-type';
|
|
14
|
+
import { componentOverridablePropTypeUtil } from '../prop-types/component-overridable-prop-type';
|
|
15
|
+
import { type OverridableProp } from '../types';
|
|
16
|
+
import { getContainerByOriginId } from './get-container-by-origin-id';
|
|
17
|
+
import { getOverridableProp } from './get-overridable-prop';
|
|
18
|
+
|
|
19
|
+
type OverridesChainResult =
|
|
20
|
+
| {
|
|
21
|
+
isChainBroken: false;
|
|
22
|
+
innerElement: V1Element;
|
|
23
|
+
overridesMapping: OverridesMapping;
|
|
24
|
+
}
|
|
25
|
+
| {
|
|
26
|
+
isChainBroken: true;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// Recursively walks down a chain of nested component instances to find the innermost element
|
|
30
|
+
// and collect the overrides mapping for it.
|
|
31
|
+
// Returns the resolved inner element with its overrides mapping,
|
|
32
|
+
// or { isChainBroken: true } if any level in the chain is no longer overridable.
|
|
33
|
+
export function resolveOverridesChain( {
|
|
34
|
+
outerOverridableProp,
|
|
35
|
+
outerInstanceId,
|
|
36
|
+
overridesMapping = {},
|
|
37
|
+
}: {
|
|
38
|
+
outerOverridableProp: OverridableProp;
|
|
39
|
+
outerInstanceId?: string;
|
|
40
|
+
overridesMapping?: OverridesMapping;
|
|
41
|
+
} ): OverridesChainResult {
|
|
42
|
+
// Stop condition: no originPropFields means we've reached the most inner component instance
|
|
43
|
+
if ( ! outerOverridableProp.originPropFields ) {
|
|
44
|
+
const innerElement = getContainerByOriginId( outerOverridableProp.elementId, outerInstanceId );
|
|
45
|
+
|
|
46
|
+
if ( ! innerElement ) {
|
|
47
|
+
throw new Error(
|
|
48
|
+
`Inner element not found inside instance. elementId: ${ outerOverridableProp.elementId }, instanceId: ${ outerInstanceId }`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return { isChainBroken: false, innerElement, overridesMapping };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Step 1: Find the intermediate component instance and read its settings.
|
|
56
|
+
const currentInstance = getContainerByOriginId( outerOverridableProp.elementId, outerInstanceId );
|
|
57
|
+
if ( ! currentInstance ) {
|
|
58
|
+
// One of the instances in the chain was deleted.
|
|
59
|
+
return { isChainBroken: true };
|
|
60
|
+
}
|
|
61
|
+
const { componentId, overrides } = extractComponentInstanceSettings( currentInstance );
|
|
62
|
+
|
|
63
|
+
if ( ! componentId ) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
`Component ID not found for current instance. currentInstanceId: ${ currentInstance.id }. outerInstanceId: ${ outerInstanceId }`
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Collect overrides from this level, translating keys for exposed-further props.
|
|
70
|
+
const mergedOverrides = buildOverridesMap( overridesMapping, overrides ?? [] );
|
|
71
|
+
|
|
72
|
+
// Find the overridable-override that matches the outer overridable prop's key,
|
|
73
|
+
// to get the next level's overridable prop.
|
|
74
|
+
const override = findOverrideByOuterKey( overrides, outerOverridableProp.overrideKey );
|
|
75
|
+
const overrideKey = componentInstanceOverridePropTypeUtil.extract( override )?.override_key;
|
|
76
|
+
|
|
77
|
+
if ( ! override || ! overrideKey ) {
|
|
78
|
+
// No matching override found for the current level - it means it's no longer overridable.
|
|
79
|
+
return { isChainBroken: true };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const overridableProp = getOverridableProp( { componentId, overrideKey } );
|
|
83
|
+
|
|
84
|
+
if ( ! overridableProp ) {
|
|
85
|
+
throw new Error( `Overridable prop not found. componentId: ${ componentId }, overrideKey: ${ overrideKey }` );
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Step 4: Recurse into the next nesting level.
|
|
89
|
+
return resolveOverridesChain( {
|
|
90
|
+
outerOverridableProp: overridableProp,
|
|
91
|
+
outerInstanceId: currentInstance.id,
|
|
92
|
+
overridesMapping: mergedOverrides,
|
|
93
|
+
} );
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Builds overrides map from instances chain:
|
|
98
|
+
* At each level, we collect overrides from the current instance and merge them with the overrides from the outer levels.
|
|
99
|
+
*
|
|
100
|
+
* For exposed-further overrides (overridable wrapping an override), we have outer key (overridable's) and inner key (override's).
|
|
101
|
+
* If a higher level already set a value for the outer key, that value is carried forward to the inner key
|
|
102
|
+
* — same logic as the componentOverridableTransformer in the render pipeline.
|
|
103
|
+
*
|
|
104
|
+
* For simple overrides, that are not exposed further, we just use the override's key and value.
|
|
105
|
+
*
|
|
106
|
+
* @param existing - Previously accumulated overrides from outer levels.
|
|
107
|
+
* @param levelOverrides - The overrides array from the current level instance.
|
|
108
|
+
*/
|
|
109
|
+
export function buildOverridesMap(
|
|
110
|
+
existing: OverridesMapping,
|
|
111
|
+
levelOverrides: ComponentInstanceOverride[]
|
|
112
|
+
): OverridesMapping {
|
|
113
|
+
const result: OverridesMapping = { ...existing };
|
|
114
|
+
|
|
115
|
+
for ( const item of levelOverrides ) {
|
|
116
|
+
const overridableValue = componentOverridablePropTypeUtil.extract( item );
|
|
117
|
+
|
|
118
|
+
if ( overridableValue ) {
|
|
119
|
+
// Exposed-further: overridable wraps an inner override with a different key.
|
|
120
|
+
const override = componentInstanceOverridePropTypeUtil.extract( overridableValue.origin_value );
|
|
121
|
+
|
|
122
|
+
if ( ! override ) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const outerKey = overridableValue.override_key;
|
|
127
|
+
const innerKey = override.override_key;
|
|
128
|
+
const innerValue = override.override_value as AnyTransformable | null;
|
|
129
|
+
|
|
130
|
+
// If an upper level already set a value for the outer key, carry it forward to the inner key.
|
|
131
|
+
const higherLevelOverride = existing[ outerKey ];
|
|
132
|
+
|
|
133
|
+
if ( higherLevelOverride ) {
|
|
134
|
+
const outerValue = higherLevelOverride.value;
|
|
135
|
+
result[ innerKey ] = {
|
|
136
|
+
value: outerValue ?? innerValue,
|
|
137
|
+
outermostKey: higherLevelOverride.outermostKey ?? outerKey,
|
|
138
|
+
};
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
result[ innerKey ] = {
|
|
143
|
+
value: innerValue,
|
|
144
|
+
outermostKey: outerKey,
|
|
145
|
+
};
|
|
146
|
+
} else {
|
|
147
|
+
// Simple override: not exposed further, we just store the override's key and value.
|
|
148
|
+
const override = componentInstanceOverridePropTypeUtil.extract( item );
|
|
149
|
+
|
|
150
|
+
if ( ! override ) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const key = override.override_key;
|
|
155
|
+
const value = override.override_value as AnyTransformable | null;
|
|
156
|
+
|
|
157
|
+
result[ key ] = { value };
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function extractComponentInstanceSettings( element: V1Element ) {
|
|
165
|
+
const instanceSetting = element.settings?.get( 'component_instance' );
|
|
166
|
+
const instanceValue = componentInstancePropTypeUtil.extract( instanceSetting );
|
|
167
|
+
const componentId = instanceValue?.component_id?.value;
|
|
168
|
+
const overrides = componentInstanceOverridesPropTypeUtil.extract( instanceValue?.overrides );
|
|
169
|
+
|
|
170
|
+
return { componentId, overrides };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Finds the inner override prop whose wrapping overridable matches the given outer key.
|
|
174
|
+
function findOverrideByOuterKey(
|
|
175
|
+
overrides: ComponentInstanceOverride[] | null | undefined,
|
|
176
|
+
outerKey: string
|
|
177
|
+
): ComponentInstanceOverrideProp | null {
|
|
178
|
+
if ( ! overrides ) {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const overridableOverride: ComponentInstanceOverride | undefined = overrides.find( ( item ) => {
|
|
183
|
+
const overridableValue = componentOverridablePropTypeUtil.extract( item );
|
|
184
|
+
if ( ! overridableValue ) {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
return overridableValue.override_key === outerKey;
|
|
188
|
+
} );
|
|
189
|
+
|
|
190
|
+
const override = componentOverridablePropTypeUtil.extract( overridableOverride )?.origin_value;
|
|
191
|
+
|
|
192
|
+
if ( ! override || ! componentInstanceOverridePropTypeUtil.isValid( override ) ) {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return override;
|
|
197
|
+
}
|