@elementor/editor-editing-panel 1.15.0 → 1.17.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 (27) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/dist/index.js +306 -232
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.mjs +211 -137
  5. package/dist/index.mjs.map +1 -1
  6. package/package.json +13 -13
  7. package/src/components/css-classes/css-class-menu.tsx +1 -1
  8. package/src/components/css-classes/css-class-selector.tsx +1 -1
  9. package/src/components/editing-panel.tsx +2 -0
  10. package/src/components/style-sections/border-section/border-radius-field.tsx +1 -0
  11. package/src/components/style-sections/border-section/border-width-field.tsx +19 -10
  12. package/src/components/style-sections/layout-section/flex-size-field.tsx +1 -1
  13. package/src/components/style-sections/position-section/dimensions-field.tsx +24 -12
  14. package/src/components/style-sections/position-section/position-section.tsx +12 -12
  15. package/src/components/style-sections/position-section/z-index-field.tsx +1 -1
  16. package/src/components/style-sections/size-section/size-section.tsx +18 -9
  17. package/src/components/style-sections/spacing-section/spacing-section.tsx +9 -2
  18. package/src/components/style-sections/typography-section/font-family-field.tsx +34 -2
  19. package/src/components/style-sections/typography-section/font-weight-field.tsx +3 -3
  20. package/src/components/style-sections/typography-section/text-direction-field.tsx +4 -2
  21. package/src/dynamics/components/dynamic-selection-control.tsx +1 -1
  22. package/src/dynamics/components/dynamic-selection.tsx +19 -12
  23. package/src/dynamics/hooks/use-prop-dynamic-action.tsx +1 -1
  24. package/src/styles-inheritance/create-snapshots-manager.ts +179 -0
  25. package/src/styles-inheritance/create-styles-inheritance.ts +50 -0
  26. package/src/styles-inheritance/types.ts +42 -0
  27. package/src/styles-inheritance/utils.ts +10 -0
@@ -0,0 +1,179 @@
1
+ import { type BreakpointId, type BreakpointNode } from '@elementor/editor-responsive';
2
+ import { type StyleDefinitionState } from '@elementor/editor-styles';
3
+
4
+ import {
5
+ type BreakpointsInheritancePath,
6
+ type BreakpointsStatesSnapshotsMapping,
7
+ type BreakpointStatesSlotsMapping,
8
+ type SnapshotPropValue,
9
+ type StyleInheritanceMetaProps,
10
+ type StylesInheritanceSnapshot,
11
+ type StylesInheritanceSnapshotGetter,
12
+ type StylesInheritanceSnapshotsSlot,
13
+ type StyleVariantWithId,
14
+ } from './types';
15
+ import { DEFAULT_STATE, getBreakpointKey, getStateKey } from './utils';
16
+
17
+ export function createSnapshotsManager(
18
+ getStylesByMeta: ( meta: StyleInheritanceMetaProps ) => StyleVariantWithId[],
19
+ breakpointsRoot: BreakpointNode
20
+ ): StylesInheritanceSnapshotGetter {
21
+ const breakpointsInheritancePaths = makeBreakpointsInheritancePaths( breakpointsRoot );
22
+ const allBreakpointStatesSnapshots: BreakpointsStatesSnapshotsMapping = {};
23
+
24
+ const buildMissingSnapshotsForBreakpoint = (
25
+ currentBreakpointId: BreakpointId | null,
26
+ parentBreakpoint: BreakpointStatesSlotsMapping | undefined,
27
+ state: StyleDefinitionState
28
+ ) => {
29
+ const currentBreakpointKey = getBreakpointKey( currentBreakpointId );
30
+ const stateKey = getStateKey( state );
31
+
32
+ if ( ! allBreakpointStatesSnapshots[ currentBreakpointKey ] ) {
33
+ allBreakpointStatesSnapshots[ currentBreakpointKey ] = {
34
+ [ DEFAULT_STATE ]: buildStateSnapshotSlot(
35
+ getStylesByMeta( { breakpoint: currentBreakpointId, state: null } ),
36
+ parentBreakpoint,
37
+ {},
38
+ null
39
+ ),
40
+ };
41
+ }
42
+
43
+ if ( state && ! allBreakpointStatesSnapshots[ currentBreakpointKey ][ stateKey ] ) {
44
+ allBreakpointStatesSnapshots[ currentBreakpointKey ][ stateKey ] = buildStateSnapshotSlot(
45
+ getStylesByMeta( { breakpoint: currentBreakpointId, state } ),
46
+ parentBreakpoint,
47
+ allBreakpointStatesSnapshots[ currentBreakpointKey ],
48
+ state
49
+ );
50
+ }
51
+ };
52
+
53
+ return ( meta: StyleInheritanceMetaProps ) => {
54
+ const { breakpoint, state } = meta;
55
+
56
+ const stateKey = getStateKey( state );
57
+ const breakpointKey = getBreakpointKey( breakpoint );
58
+
59
+ if ( allBreakpointStatesSnapshots[ breakpointKey ]?.[ stateKey ] ) {
60
+ // snapshot was already made for this breakpoint+state
61
+ return allBreakpointStatesSnapshots[ breakpointKey ][ stateKey ].snapshot;
62
+ }
63
+
64
+ const breakpointsChain = [ ...breakpointsInheritancePaths[ breakpointKey ], breakpoint ];
65
+
66
+ breakpointsChain.forEach( ( breakpointId, index ) => {
67
+ const parentBreakpointId = index > 0 ? breakpointsChain[ index - 1 ] : null;
68
+
69
+ buildMissingSnapshotsForBreakpoint(
70
+ breakpointId,
71
+ parentBreakpointId ? allBreakpointStatesSnapshots[ parentBreakpointId ] : undefined,
72
+ state
73
+ );
74
+ } );
75
+
76
+ return allBreakpointStatesSnapshots[ breakpointKey ]?.[ stateKey ]?.snapshot;
77
+ };
78
+ }
79
+
80
+ /**
81
+ * builds a mapping of each breakpoint to its inheritance chain, e.g. -
82
+ * desktop: [],
83
+ * tablet: [ 'desktop' ],
84
+ * mobile: [ 'desktop', 'tablet' ]
85
+ * @param root
86
+ */
87
+ function makeBreakpointsInheritancePaths( root: BreakpointNode ): BreakpointsInheritancePath {
88
+ const breakpoints: Partial< BreakpointsInheritancePath > = {};
89
+
90
+ const traverse = ( node: BreakpointNode, parent?: BreakpointId[] ) => {
91
+ const { id, children } = node;
92
+
93
+ breakpoints[ id ] = parent ? [ ...parent ] : [];
94
+
95
+ children?.forEach( ( child ) => {
96
+ traverse( child, [ ...( breakpoints[ id ] ?? [] ), id ] );
97
+ } );
98
+ };
99
+
100
+ traverse( root );
101
+
102
+ return breakpoints as BreakpointsInheritancePath;
103
+ }
104
+
105
+ // creates a snapshot slot for a specific breakpoint and state
106
+ function buildStateSnapshotSlot(
107
+ styles: StyleVariantWithId[],
108
+ parentBreakpoint: BreakpointStatesSlotsMapping | undefined,
109
+ currentBreakpoint: BreakpointStatesSlotsMapping,
110
+ state: StyleDefinitionState
111
+ ): StylesInheritanceSnapshotsSlot {
112
+ const initialSlot = buildInitialSnapshotFromStyles( styles );
113
+
114
+ if ( ! state ) {
115
+ return {
116
+ snapshot: mergeSnapshots( [ initialSlot.snapshot, parentBreakpoint?.[ DEFAULT_STATE ]?.snapshot ] ),
117
+ stateSpecificSnapshot: undefined,
118
+ };
119
+ }
120
+
121
+ return {
122
+ snapshot: mergeSnapshots( [
123
+ initialSlot.snapshot,
124
+ parentBreakpoint?.[ state ]?.stateSpecificSnapshot,
125
+ currentBreakpoint[ DEFAULT_STATE ]?.snapshot,
126
+ ] ),
127
+ stateSpecificSnapshot: mergeSnapshots( [
128
+ initialSlot.stateSpecificSnapshot,
129
+ parentBreakpoint?.[ state ]?.stateSpecificSnapshot,
130
+ ] ),
131
+ };
132
+ }
133
+
134
+ // creates an initial snapshot based on the passed style variants only
135
+ function buildInitialSnapshotFromStyles( styles: StyleVariantWithId[] ): StylesInheritanceSnapshotsSlot {
136
+ const snapshot: StylesInheritanceSnapshot = {};
137
+
138
+ styles.forEach( ( styleVariantWithId ) => {
139
+ const {
140
+ styleVariant: { props },
141
+ } = styleVariantWithId;
142
+
143
+ Object.entries( props ).forEach( ( [ key, value ] ) => {
144
+ if ( ! snapshot[ key ] ) {
145
+ snapshot[ key ] = [];
146
+ }
147
+
148
+ const snapshotPropValue: SnapshotPropValue = {
149
+ ...styleVariantWithId,
150
+ value,
151
+ };
152
+
153
+ snapshot[ key ].push( snapshotPropValue );
154
+ } );
155
+ } );
156
+
157
+ return {
158
+ snapshot,
159
+ stateSpecificSnapshot: snapshot,
160
+ };
161
+ }
162
+
163
+ // merge previous snapshot into the current one - first value of each prop is the strongest
164
+ function mergeSnapshots( snapshots: ( StylesInheritanceSnapshot | undefined )[] ) {
165
+ const snapshot: StylesInheritanceSnapshot = {};
166
+
167
+ snapshots.filter( Boolean ).forEach( ( currentSnapshot ) =>
168
+ Object.entries( currentSnapshot as StylesInheritanceSnapshot ).forEach( ( [ key, values ] ) => {
169
+ if ( ! snapshot[ key ] ) {
170
+ snapshot[ key ] = [];
171
+ }
172
+
173
+ // concatenate the previous snapshot's prop values to the current ones
174
+ snapshot[ key ] = snapshot[ key ].concat( values );
175
+ } )
176
+ );
177
+
178
+ return snapshot;
179
+ }
@@ -0,0 +1,50 @@
1
+ import { type BreakpointNode } from '@elementor/editor-responsive';
2
+ import { type StyleDefinition } from '@elementor/editor-styles';
3
+
4
+ import { createSnapshotsManager } from './create-snapshots-manager';
5
+ import { type BreakpointsStatesStyles, type StyleInheritanceMetaProps, type StylesInheritanceSnapshot } from './types';
6
+ import { getBreakpointKey, getStateKey } from './utils';
7
+
8
+ export function createStylesInheritance(
9
+ styleDefs: StyleDefinition[],
10
+ breakpointsRoot: BreakpointNode
11
+ ): ( meta: StyleInheritanceMetaProps ) => StylesInheritanceSnapshot | undefined {
12
+ const styleVariantsByMeta = buildStyleVariantsByMetaMapping( styleDefs );
13
+
14
+ const getStyles = ( { breakpoint, state }: StyleInheritanceMetaProps ) =>
15
+ styleVariantsByMeta?.[ getBreakpointKey( breakpoint ) ]?.[ getStateKey( state ) ] ?? [];
16
+
17
+ return createSnapshotsManager( getStyles, breakpointsRoot );
18
+ }
19
+
20
+ function buildStyleVariantsByMetaMapping( styleDefs: StyleDefinition[] ): BreakpointsStatesStyles {
21
+ const breakpointStateSlots: BreakpointsStatesStyles = {};
22
+
23
+ styleDefs.forEach( ( styleDef ) => {
24
+ // iterate over each style definition's variants and place them in the corresponding breakpoint's base or state styles
25
+ styleDef.variants.forEach( ( styleVariant ) => {
26
+ const { meta } = styleVariant;
27
+ const { state, breakpoint } = meta;
28
+
29
+ const breakpointKey = getBreakpointKey( breakpoint );
30
+ const stateKey = getStateKey( state );
31
+
32
+ if ( ! breakpointStateSlots[ breakpointKey ] ) {
33
+ breakpointStateSlots[ breakpointKey ] = {};
34
+ }
35
+
36
+ const breakpointNode = breakpointStateSlots[ breakpointKey ];
37
+
38
+ if ( ! breakpointNode[ stateKey ] ) {
39
+ breakpointNode[ stateKey ] = [];
40
+ }
41
+
42
+ breakpointNode[ stateKey ].push( {
43
+ styleId: styleDef.id,
44
+ styleVariant,
45
+ } );
46
+ } );
47
+ } );
48
+
49
+ return breakpointStateSlots;
50
+ }
@@ -0,0 +1,42 @@
1
+ import { type PropValue } from '@elementor/editor-props';
2
+ import { type BreakpointId } from '@elementor/editor-responsive';
3
+ import { type StyleDefinitionState, type StyleDefinitionVariant } from '@elementor/editor-styles';
4
+
5
+ export type StyleDefinitionStateWithNormal = NonNullable< StyleDefinitionState > | 'normal';
6
+
7
+ type StatesMapping< T > = Partial< Record< StyleDefinitionStateWithNormal, T > >;
8
+
9
+ export type StyleVariantWithId = {
10
+ styleId: string;
11
+ styleVariant: StyleDefinitionVariant;
12
+ };
13
+
14
+ export type SnapshotPropValue = StyleVariantWithId & {
15
+ value: PropValue;
16
+ };
17
+
18
+ export type StylesInheritanceSnapshot = Record< string, SnapshotPropValue[] >;
19
+
20
+ export type StylesInheritanceSnapshotsSlot = {
21
+ snapshot?: StylesInheritanceSnapshot;
22
+ stateSpecificSnapshot?: StylesInheritanceSnapshot; // with only prop values of the current state, used for inheritance - e.g. mobile-hover inherits first from tablet-hover specific snapshot
23
+ };
24
+
25
+ export type BreakpointStatesSlotsMapping = StatesMapping< StylesInheritanceSnapshotsSlot >;
26
+
27
+ export type BreakpointsStatesSnapshotsMapping = Partial< Record< BreakpointId, BreakpointStatesSlotsMapping > >;
28
+
29
+ type BreakpointStatesStyles = StatesMapping< StyleVariantWithId[] >;
30
+
31
+ export type BreakpointsStatesStyles = Partial< Record< BreakpointId, Partial< BreakpointStatesStyles > > >;
32
+
33
+ export type BreakpointsInheritancePath = Record< BreakpointId, BreakpointId[] >;
34
+
35
+ export type StyleInheritanceMetaProps = {
36
+ breakpoint: BreakpointId | null;
37
+ state: StyleDefinitionState;
38
+ };
39
+
40
+ export type StylesInheritanceSnapshotGetter = (
41
+ meta: StyleInheritanceMetaProps
42
+ ) => StylesInheritanceSnapshot | undefined;
@@ -0,0 +1,10 @@
1
+ import { type BreakpointId } from '@elementor/editor-responsive';
2
+ import { type StyleDefinitionState } from '@elementor/editor-styles';
3
+
4
+ export const DEFAULT_STATE = 'normal';
5
+
6
+ const DEFAULT_BREAKPOINT = 'desktop';
7
+
8
+ export const getStateKey = ( state: StyleDefinitionState ) => state ?? DEFAULT_STATE;
9
+
10
+ export const getBreakpointKey = ( breakpoint: BreakpointId | null ): BreakpointId => breakpoint ?? DEFAULT_BREAKPOINT;