@elementor/editor-components 4.0.0-543 → 4.0.0-545

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 (25) hide show
  1. package/dist/index.js +739 -590
  2. package/dist/index.js.map +1 -1
  3. package/dist/index.mjs +676 -527
  4. package/dist/index.mjs.map +1 -1
  5. package/package.json +22 -22
  6. package/src/components/component-panel-header/component-panel-header.tsx +2 -2
  7. package/src/components/component-properties-panel/component-properties-panel-content.tsx +2 -2
  8. package/src/components/component-properties-panel/use-current-editable-item.ts +1 -2
  9. package/src/components/edit-component/edit-component.tsx +3 -0
  10. package/src/components/instance-editing-panel/instance-editing-panel.tsx +11 -9
  11. package/src/components/instance-editing-panel/override-prop-control.tsx +60 -44
  12. package/src/components/instance-editing-panel/override-props-group.tsx +3 -10
  13. package/src/components/instance-editing-panel/use-resolved-origin-value.tsx +6 -19
  14. package/src/components/overridable-props/overridable-prop-indicator.tsx +3 -2
  15. package/src/hooks/use-sanitize-overridable-props.ts +31 -0
  16. package/src/provider/component-instance-context.tsx +21 -0
  17. package/src/store/actions/create-unpublished-component.ts +12 -2
  18. package/src/store/actions/reset-sanitized-components.ts +7 -0
  19. package/src/store/actions/update-component-sanitized-attribute.ts +8 -0
  20. package/src/store/store.ts +35 -0
  21. package/src/sync/handle-component-edit-mode-container.ts +1 -1
  22. package/src/utils/filter-valid-overridable-props.ts +84 -0
  23. package/src/utils/overridable-props-utils.ts +58 -0
  24. package/src/utils/tracking.ts +5 -1
  25. package/src/components/component-panel-header/use-overridable-props.ts +0 -14
@@ -21,6 +21,8 @@ type GetComponentResponse = PublishedComponent[];
21
21
 
22
22
  type Status = 'idle' | 'pending' | 'error';
23
23
 
24
+ export type SanitizeAttributes = 'overridableProps';
25
+
24
26
  type ComponentsState = {
25
27
  data: PublishedComponent[];
26
28
  unpublishedData: UnpublishedComponent[];
@@ -31,6 +33,10 @@ type ComponentsState = {
31
33
  path: ComponentsPathItem[];
32
34
  currentComponentId: V1Document[ 'id' ] | null;
33
35
  updatedComponentNames: Record< number, string >;
36
+
37
+ // We use this map to flag any sanitized attribute of a given component
38
+ // This map currently resets in response to the `editor/documents/open` command
39
+ sanitized: Record< ComponentId, Partial< Record< SanitizeAttributes, boolean > > >;
34
40
  };
35
41
 
36
42
  export type ComponentsSlice = SliceState< typeof slice >;
@@ -51,6 +57,7 @@ export const initialState: ComponentsState = {
51
57
  path: [],
52
58
  currentComponentId: null,
53
59
  updatedComponentNames: {},
60
+ sanitized: {},
54
61
  };
55
62
 
56
63
  export const SLICE_NAME = 'components';
@@ -135,6 +142,21 @@ export const slice = createSlice( {
135
142
  cleanUpdatedComponentNames: ( state ) => {
136
143
  state.updatedComponentNames = {};
137
144
  },
145
+ updateComponentSanitizedAttribute: (
146
+ state,
147
+ {
148
+ payload: { componentId, attribute },
149
+ }: PayloadAction< { componentId: ComponentId; attribute: SanitizeAttributes } >
150
+ ) => {
151
+ if ( ! state.sanitized[ componentId ] ) {
152
+ state.sanitized[ componentId ] = {};
153
+ }
154
+
155
+ state.sanitized[ componentId ][ attribute ] = true;
156
+ },
157
+ resetSanitizedComponents: ( state ) => {
158
+ state.sanitized = {};
159
+ },
138
160
  },
139
161
  extraReducers: ( builder ) => {
140
162
  builder.addCase( loadComponents.fulfilled, ( state, { payload }: PayloadAction< GetComponentResponse > ) => {
@@ -248,3 +270,16 @@ export const selectUpdatedComponentNames = createSelector(
248
270
  title,
249
271
  } ) )
250
272
  );
273
+
274
+ const useSanitizedComponents = () => {
275
+ return useSelector( ( state: ComponentsSlice ) => state[ SLICE_NAME ].sanitized );
276
+ };
277
+ export const useIsSanitizedComponent = ( componentId: ComponentId | null, key: SanitizeAttributes ) => {
278
+ const sanitizedComponents = useSanitizedComponents();
279
+
280
+ if ( ! componentId ) {
281
+ return false;
282
+ }
283
+
284
+ return !! sanitizedComponents[ componentId ]?.[ key ];
285
+ };
@@ -86,7 +86,7 @@ function initRedirectDropIntoComponent() {
86
86
 
87
87
  function createEmptyTopLevelContainer( container: Container ) {
88
88
  const newContainer = createElement( {
89
- containerId: container.id,
89
+ container,
90
90
  model: { elType: V4_DEFAULT_CONTAINER_TYPE },
91
91
  } );
92
92
 
@@ -0,0 +1,84 @@
1
+ import { getElementSetting } from '@elementor/editor-elements';
2
+
3
+ import { getOverridableProp } from '../components/overridable-props/utils/get-overridable-prop';
4
+ import { type ComponentInstanceOverride } from '../prop-types/component-instance-overrides-prop-type';
5
+ import { componentInstanceOverridesPropTypeUtil } from '../prop-types/component-instance-overrides-prop-type';
6
+ import { componentInstancePropTypeUtil } from '../prop-types/component-instance-prop-type';
7
+ import { componentOverridablePropTypeUtil } from '../prop-types/component-overridable-prop-type';
8
+ import { type OverridableProp, type OverridableProps } from '../types';
9
+ import { extractInnerOverrideInfo } from './overridable-props-utils';
10
+
11
+ export function filterValidOverridableProps( overridableProps: OverridableProps ): OverridableProps {
12
+ const validProps: Record< string, OverridableProp > = {};
13
+
14
+ for ( const [ key, prop ] of Object.entries( overridableProps.props ) ) {
15
+ if ( isExposedPropValid( prop ) ) {
16
+ validProps[ key ] = prop;
17
+ }
18
+ }
19
+
20
+ const validPropKeys = new Set( Object.keys( validProps ) );
21
+ const filteredGroups = {
22
+ items: Object.fromEntries(
23
+ Object.entries( overridableProps.groups.items ).map( ( [ groupId, group ] ) => [
24
+ groupId,
25
+ { ...group, props: group.props.filter( ( propKey ) => validPropKeys.has( propKey ) ) },
26
+ ] )
27
+ ),
28
+ order: overridableProps.groups.order,
29
+ };
30
+
31
+ return { props: validProps, groups: filteredGroups };
32
+ }
33
+
34
+ export function isExposedPropValid( prop: OverridableProp ): boolean {
35
+ if ( ! prop.originPropFields ) {
36
+ // if no originPropFields - the prop is on the widget level itself, therefore no need to lookup for a corresponding component's overridables
37
+ return true;
38
+ }
39
+
40
+ const setting = getElementSetting( prop.elementId, 'component_instance' );
41
+ const componentInstance = componentInstancePropTypeUtil.extract( setting );
42
+
43
+ if ( ! componentInstance?.component_id?.value ) {
44
+ return false;
45
+ }
46
+
47
+ const overrides = componentInstanceOverridesPropTypeUtil.extract( componentInstance.overrides ) ?? undefined;
48
+ const matchingOverride = findOverrideByOuterKey( overrides, prop.overrideKey );
49
+ const innerOverrideInfo = extractInnerOverrideInfo( matchingOverride );
50
+
51
+ if ( ! innerOverrideInfo ) {
52
+ return false;
53
+ }
54
+
55
+ const { componentId, innerOverrideKey } = innerOverrideInfo;
56
+ const innerOverridableProp = getOverridableProp( { componentId, overrideKey: innerOverrideKey } );
57
+
58
+ if ( ! innerOverridableProp ) {
59
+ return false;
60
+ }
61
+
62
+ return isExposedPropValid( innerOverridableProp );
63
+ }
64
+
65
+ function findOverrideByOuterKey(
66
+ overrides: ComponentInstanceOverride[] | undefined,
67
+ outerKey: string
68
+ ): ComponentInstanceOverride | null {
69
+ if ( ! overrides ) {
70
+ return null;
71
+ }
72
+
73
+ return (
74
+ overrides.find( ( override ) => {
75
+ const overridableValue = componentOverridablePropTypeUtil.extract( override );
76
+
77
+ if ( overridableValue ) {
78
+ return overridableValue.override_key === outerKey;
79
+ }
80
+
81
+ return override.value.override_key === outerKey;
82
+ } ) ?? null
83
+ );
84
+ }
@@ -0,0 +1,58 @@
1
+ import { componentInstanceOverridePropTypeUtil } from '../prop-types/component-instance-override-prop-type';
2
+ import {
3
+ type ComponentInstanceOverride,
4
+ type ComponentInstanceOverridesPropValue,
5
+ } from '../prop-types/component-instance-overrides-prop-type';
6
+ import { componentOverridablePropTypeUtil } from '../prop-types/component-overridable-prop-type';
7
+
8
+ export type InnerOverrideInfo = {
9
+ componentId: number;
10
+ innerOverrideKey: string;
11
+ overrideValue: unknown;
12
+ };
13
+
14
+ export function getMatchingOverride(
15
+ overrides: ComponentInstanceOverridesPropValue,
16
+ overrideKey: string
17
+ ): ComponentInstanceOverride | null {
18
+ return (
19
+ overrides?.find( ( override ) => {
20
+ const overridableValue = componentOverridablePropTypeUtil.extract( override );
21
+
22
+ if ( overridableValue ) {
23
+ const overrideValue = componentInstanceOverridePropTypeUtil.extract( overridableValue.origin_value );
24
+ return overrideValue?.override_key === overrideKey;
25
+ }
26
+
27
+ return override.value.override_key === overrideKey;
28
+ } ) ?? null
29
+ );
30
+ }
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
+ }
@@ -5,7 +5,7 @@ import { __getState as getState } from '@elementor/store';
5
5
  import { selectCreatedThisSession } from '../store/store';
6
6
  import { type ExtendedWindow } from '../types';
7
7
 
8
- export type Source = 'user' | 'mcp_tool';
8
+ export type Source = 'user' | 'mcp_tool' | 'system';
9
9
 
10
10
  type ComponentEventData = Record< string, unknown > & {
11
11
  action:
@@ -24,6 +24,10 @@ type ComponentEventData = Record< string, unknown > & {
24
24
  const FEATURE_NAME = 'Components';
25
25
 
26
26
  export const trackComponentEvent = ( { action, source, ...data }: ComponentEventData ) => {
27
+ if ( source === 'system' ) {
28
+ return;
29
+ }
30
+
27
31
  const { dispatchEvent, config } = getMixpanel();
28
32
  if ( ! config?.names?.components?.[ action ] ) {
29
33
  return;
@@ -1,14 +0,0 @@
1
- import { __useSelector as useSelector } from '@elementor/store';
2
-
3
- import { type ComponentsSlice, selectOverridableProps } from '../../store/store';
4
- import { type ComponentId, type OverridableProps } from '../../types';
5
-
6
- export function useOverridableProps( componentId: ComponentId | null ): OverridableProps | undefined {
7
- return useSelector( ( state: ComponentsSlice ) => {
8
- if ( ! componentId ) {
9
- return undefined;
10
- }
11
-
12
- return selectOverridableProps( state, componentId );
13
- } );
14
- }