@elementor/editor-components 3.33.0-181 → 3.33.0-183

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.
@@ -0,0 +1,51 @@
1
+ import { type V1ElementData } from '@elementor/editor-elements';
2
+ import { type StyleDefinition } from '@elementor/editor-styles';
3
+ import { __dispatch as dispatch, __getState as getState } from '@elementor/store';
4
+
5
+ import { apiClient } from '../api';
6
+ import { type ComponentId, type Element } from '../types';
7
+ import { getComponentIds } from '../utils/get-component-ids';
8
+ import { selectStyles, slice } from './store';
9
+
10
+ export async function loadComponentsStyles( elements: Element[] ) {
11
+ const componentIds = Array.from( new Set( getComponentIds( elements ) ) );
12
+
13
+ if ( ! componentIds.length ) {
14
+ return;
15
+ }
16
+
17
+ const knownComponents = selectStyles( getState() );
18
+ const unknownComponentIds = componentIds.filter( ( id ) => ! knownComponents[ id ] );
19
+
20
+ if ( ! unknownComponentIds.length ) {
21
+ return;
22
+ }
23
+
24
+ addComponentStyles( unknownComponentIds );
25
+ }
26
+
27
+ async function addComponentStyles( ids: ComponentId[] ) {
28
+ const newComponents = await loadStyles( ids );
29
+
30
+ addStyles( newComponents );
31
+
32
+ Object.values( newComponents ).forEach( ( [ , data ] ) => {
33
+ loadComponentsStyles( data.elements as Element[] );
34
+ } );
35
+ }
36
+
37
+ async function loadStyles( ids: number[] ): Promise< [ number, V1ElementData ][] > {
38
+ return Promise.all( ids.map( async ( id ) => [ id, await apiClient.getComponentConfig( id ) ] ) );
39
+ }
40
+
41
+ function addStyles( data: ( readonly [ ComponentId, V1ElementData ] )[] ) {
42
+ const styles = Object.fromEntries(
43
+ data.map( ( [ componentId, componentData ] ) => [ componentId, extractStyles( componentData ) ] )
44
+ );
45
+
46
+ dispatch( slice.actions.addStyles( styles ) );
47
+ }
48
+
49
+ function extractStyles( element: V1ElementData ): Array< StyleDefinition > {
50
+ return [ ...Object.values( element.styles ?? {} ), ...( element.elements ?? [] ).flatMap( extractStyles ) ];
51
+ }
@@ -0,0 +1,9 @@
1
+ import { __dispatch as dispatch } from '@elementor/store';
2
+
3
+ import { apiClient } from '../api';
4
+ import { slice } from './store';
5
+
6
+ export function removeComponentStyles( id: number ) {
7
+ apiClient.invalidateComponentConfigCache( id );
8
+ dispatch( slice.actions.removeStyles( { id } ) );
9
+ }
@@ -5,35 +5,48 @@ import {
5
5
  type SliceState,
6
6
  } from '@elementor/store';
7
7
 
8
+ import { type Component, type ComponentId, type StylesDefinition } from '../types';
8
9
  import { createComponent, loadComponents } from './thunks';
9
- import { type Component } from './types';
10
10
 
11
11
  type GetComponentResponse = Component[];
12
12
 
13
13
  type Status = 'idle' | 'pending' | 'error';
14
- export type ComponentsState = {
14
+
15
+ type ComponentsState = {
15
16
  data: Component[];
16
17
  loadStatus: Status;
17
18
  createStatus: Status;
19
+ styles: StylesDefinition;
18
20
  };
19
21
 
22
+ type ComponentsSlice = SliceState< typeof slice >;
23
+
20
24
  export const initialState: ComponentsState = {
21
25
  data: [],
22
26
  loadStatus: 'idle',
23
27
  createStatus: 'idle',
28
+ styles: {},
24
29
  };
25
30
 
26
- const SLICE_NAME = 'components';
31
+ export const SLICE_NAME = 'components';
27
32
  export const slice = createSlice( {
28
33
  name: SLICE_NAME,
29
34
  initialState,
30
35
  reducers: {
31
36
  add: ( state, { payload } ) => {
32
- state.data.push( payload );
37
+ state.data = { ...payload };
33
38
  },
34
39
  load: ( state, { payload } ) => {
35
40
  state.data = payload;
36
41
  },
42
+ removeStyles( state, { payload }: PayloadAction< { id: ComponentId } > ) {
43
+ const { [ payload.id ]: _, ...rest } = state.styles;
44
+
45
+ state.styles = rest;
46
+ },
47
+ addStyles: ( state, { payload } ) => {
48
+ state.styles = { ...state.styles, ...payload };
49
+ },
37
50
  },
38
51
  extraReducers: ( builder ) => {
39
52
  builder.addCase( loadComponents.fulfilled, ( state, { payload }: PayloadAction< GetComponentResponse > ) => {
@@ -62,12 +75,15 @@ export const slice = createSlice( {
62
75
  },
63
76
  } );
64
77
 
65
- const selectData = ( state: SliceState< typeof slice > ) => state[ SLICE_NAME ].data;
66
- const selectLoadStatus = ( state: SliceState< typeof slice > ) => state[ SLICE_NAME ].loadStatus;
67
- const selectCreateStatus = ( state: SliceState< typeof slice > ) => state[ SLICE_NAME ].createStatus;
78
+ const selectData = ( state: ComponentsSlice ) => state[ SLICE_NAME ].data;
79
+ const selectLoadStatus = ( state: ComponentsSlice ) => state[ SLICE_NAME ].loadStatus;
80
+ const selectCreateStatus = ( state: ComponentsSlice ) => state[ SLICE_NAME ].createStatus;
81
+ const selectStylesDefinitions = ( state: ComponentsSlice ) => state[ SLICE_NAME ].styles ?? {};
68
82
 
69
83
  export const selectComponents = createSelector( selectData, ( data: Component[] ) => data );
70
84
  export const selectLoadIsPending = createSelector( selectLoadStatus, ( status ) => status === 'pending' );
71
85
  export const selectLoadIsError = createSelector( selectLoadStatus, ( status ) => status === 'error' );
72
86
  export const selectCreateIsPending = createSelector( selectCreateStatus, ( status ) => status === 'pending' );
73
87
  export const selectCreateIsError = createSelector( selectCreateStatus, ( status ) => status === 'error' );
88
+ export const selectStyles = ( state: ComponentsSlice ) => state[ SLICE_NAME ].styles ?? {};
89
+ export const selectFlatStyles = createSelector( selectStylesDefinitions, ( data ) => Object.values( data ).flat() );
@@ -1,6 +1,6 @@
1
1
  import { __createAsyncThunk as createAsyncThunk } from '@elementor/store';
2
2
 
3
- import { apiClient, type CreateComponentPayload, type CreateComponentResponse } from './api';
3
+ import { apiClient, type CreateComponentPayload, type CreateComponentResponse } from '../api';
4
4
 
5
5
  const createComponent = createAsyncThunk< CreateComponentResponse, CreateComponentPayload >(
6
6
  'components/create',
package/src/types.ts CHANGED
@@ -1,8 +1,23 @@
1
+ import { type V1ElementModelProps, type V1ElementSettingsProps } from '@elementor/editor-elements';
2
+ import { type NumberPropValue } from '@elementor/editor-props';
3
+ import type { StyleDefinition } from '@elementor/editor-styles';
4
+
1
5
  export type ComponentFormValues = {
2
6
  componentName: string;
3
7
  };
4
8
 
9
+ export type ComponentId = number;
10
+
11
+ export type StylesDefinition = Record< ComponentId, StyleDefinition[] >;
12
+
5
13
  export type Component = {
6
14
  id: number;
7
15
  name: string;
8
16
  };
17
+
18
+ export type Element = V1ElementModelProps & {
19
+ elements?: Element[];
20
+ settings?: V1ElementSettingsProps & {
21
+ component_id?: NumberPropValue;
22
+ };
23
+ };
@@ -0,0 +1,24 @@
1
+ import { type V1ElementData } from '@elementor/editor-elements';
2
+ import { isTransformable } from '@elementor/editor-props';
3
+
4
+ export const getComponentIds = ( elements: V1ElementData[] ) => {
5
+ return elements.flatMap( ( element ) => {
6
+ const ids: number[] = [];
7
+
8
+ const type = element.widgetType || element.elType;
9
+
10
+ if (
11
+ type === 'e-component' &&
12
+ element.settings?.component_id &&
13
+ isTransformable( element.settings?.component_id )
14
+ ) {
15
+ ids.push( element.settings.component_id.value );
16
+ }
17
+
18
+ if ( element.elements ) {
19
+ ids.push( ...getComponentIds( element.elements ) );
20
+ }
21
+
22
+ return ids;
23
+ } );
24
+ };