@elementor/editor-editing-panel 1.24.0 → 1.28.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.
- package/CHANGELOG.md +102 -0
- package/dist/index.d.mts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +448 -309
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +426 -287
- package/dist/index.mjs.map +1 -1
- package/package.json +11 -10
- package/src/components/css-classes/css-class-item.tsx +8 -10
- package/src/components/css-classes/css-class-menu.tsx +60 -12
- package/src/components/css-classes/css-class-selector.tsx +28 -27
- package/src/components/editing-panel-tabs.tsx +1 -8
- package/src/components/multi-combobox.tsx +3 -0
- package/src/components/style-indicator.tsx +23 -0
- package/src/components/style-sections/border-section/border-radius-field.tsx +4 -5
- package/src/components/style-sections/border-section/border-width-field.tsx +2 -3
- package/src/components/style-sections/layout-section/display-field.tsx +34 -28
- package/src/components/style-sections/layout-section/flex-size-field.tsx +28 -18
- package/src/components/style-sections/layout-section/layout-section.tsx +14 -2
- package/src/components/style-sections/typography-section/text-alignment-field.tsx +5 -6
- package/src/components/style-tab.tsx +2 -19
- package/src/contexts/style-context.tsx +2 -2
- package/src/controls-registry/control-type-container.tsx +2 -2
- package/src/controls-registry/styles-field.tsx +9 -2
- package/src/dynamics/dynamic-transformer.ts +61 -0
- package/src/dynamics/errors.ts +6 -0
- package/src/dynamics/init.ts +6 -0
- package/src/dynamics/types.ts +17 -0
- package/src/hooks/use-active-style-def-id.ts +36 -0
- package/src/hooks/use-styles-fields.ts +7 -7
- package/src/index.ts +1 -3
- package/src/init.ts +1 -1
- package/src/styles-inheritance/create-snapshots-manager.ts +16 -9
- package/src/styles-inheritance/create-styles-inheritance.ts +8 -4
- package/src/styles-inheritance/styles-inheritance-indicator.tsx +13 -31
- package/src/styles-inheritance/types.ts +7 -6
|
@@ -6,14 +6,14 @@ import {
|
|
|
6
6
|
SizeControl,
|
|
7
7
|
type ToggleButtonGroupItem,
|
|
8
8
|
} from '@elementor/editor-controls';
|
|
9
|
-
import type
|
|
9
|
+
import { numberPropTypeUtil, type NumberPropValue, type SizePropValue } from '@elementor/editor-props';
|
|
10
10
|
import { ExpandIcon, PencilIcon, ShrinkIcon } from '@elementor/icons';
|
|
11
|
-
import { DirectionProvider, Grid, ThemeProvider
|
|
11
|
+
import { DirectionProvider, Grid, ThemeProvider } from '@elementor/ui';
|
|
12
12
|
import { __ } from '@wordpress/i18n';
|
|
13
13
|
|
|
14
14
|
import { StylesField } from '../../../controls-registry/styles-field';
|
|
15
15
|
import { useDirection } from '../../../hooks/use-direction';
|
|
16
|
-
import {
|
|
16
|
+
import { useStylesFields } from '../../../hooks/use-styles-fields';
|
|
17
17
|
import { ControlLabel } from '../../control-label';
|
|
18
18
|
import { SectionContent } from '../../section-content';
|
|
19
19
|
|
|
@@ -43,45 +43,55 @@ const items: ToggleButtonGroupItem< GroupItem >[] = [
|
|
|
43
43
|
];
|
|
44
44
|
|
|
45
45
|
export const FlexSizeField = () => {
|
|
46
|
-
const { isSiteRtl } = useDirection()
|
|
47
|
-
[ growField, setGrowField ] = useStylesField< NumberPropValue | null >( 'flex-grow' ),
|
|
48
|
-
[ shrinkField, setShrinkField ] = useStylesField< NumberPropValue | null >( 'flex-shrink' ),
|
|
49
|
-
[ basisField, setBasisField ] = useStylesField< SizePropValue | null >( 'flex-basis' );
|
|
46
|
+
const { isSiteRtl } = useDirection();
|
|
50
47
|
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
const [ fields, setFields ] = useStylesFields< {
|
|
49
|
+
'flex-grow': NumberPropValue | null;
|
|
50
|
+
'flex-shrink': NumberPropValue | null;
|
|
51
|
+
'flex-basis': SizePropValue | null;
|
|
52
|
+
} >( [ 'flex-grow', 'flex-shrink', 'flex-basis' ] );
|
|
53
|
+
|
|
54
|
+
const grow = fields?.[ 'flex-grow' ]?.value || null;
|
|
55
|
+
const shrink = fields?.[ 'flex-shrink' ]?.value || null;
|
|
56
|
+
const basis = fields?.[ 'flex-basis' ]?.value || null;
|
|
54
57
|
|
|
55
58
|
const currentGroup = useMemo( () => getActiveGroup( { grow, shrink, basis } ), [ grow, shrink, basis ] ),
|
|
56
59
|
[ activeGroup, setActiveGroup ] = useState( currentGroup );
|
|
57
60
|
|
|
58
61
|
const onChangeGroup = ( group: GroupItem | null = null ) => {
|
|
59
62
|
setActiveGroup( group );
|
|
60
|
-
setBasisField( null );
|
|
61
63
|
|
|
62
64
|
if ( ! group || group === 'custom' ) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
setFields( {
|
|
66
|
+
'flex-basis': null,
|
|
67
|
+
'flex-grow': null,
|
|
68
|
+
'flex-shrink': null,
|
|
69
|
+
} );
|
|
65
70
|
|
|
66
71
|
return;
|
|
67
72
|
}
|
|
68
73
|
|
|
69
74
|
if ( group === 'flex-grow' ) {
|
|
70
|
-
|
|
71
|
-
|
|
75
|
+
setFields( {
|
|
76
|
+
'flex-basis': null,
|
|
77
|
+
'flex-grow': numberPropTypeUtil.create( DEFAULT ),
|
|
78
|
+
'flex-shrink': null,
|
|
79
|
+
} );
|
|
72
80
|
|
|
73
81
|
return;
|
|
74
82
|
}
|
|
75
83
|
|
|
76
|
-
|
|
77
|
-
|
|
84
|
+
setFields( {
|
|
85
|
+
'flex-basis': null,
|
|
86
|
+
'flex-grow': null,
|
|
87
|
+
'flex-shrink': numberPropTypeUtil.create( DEFAULT ),
|
|
88
|
+
} );
|
|
78
89
|
};
|
|
79
90
|
|
|
80
91
|
return (
|
|
81
92
|
<DirectionProvider rtl={ isSiteRtl }>
|
|
82
93
|
<ThemeProvider>
|
|
83
94
|
<SectionContent>
|
|
84
|
-
<Typography fontSize="large">{ activeGroup }</Typography>
|
|
85
95
|
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
86
96
|
<Grid item xs={ 6 }>
|
|
87
97
|
<StylesField bind={ activeGroup ?? '' }>
|
|
@@ -12,7 +12,7 @@ import { SectionContent } from '../../section-content';
|
|
|
12
12
|
import { AlignContentField } from './align-content-field';
|
|
13
13
|
import { AlignItemsField } from './align-items-field';
|
|
14
14
|
import { AlignSelfChild } from './align-self-child-field';
|
|
15
|
-
import { DisplayField } from './display-field';
|
|
15
|
+
import { DisplayField, useDisplayPlaceholderValue } from './display-field';
|
|
16
16
|
import { FlexDirectionField } from './flex-direction-field';
|
|
17
17
|
import { FlexOrderField } from './flex-order-field';
|
|
18
18
|
import { FlexSizeField } from './flex-size-field';
|
|
@@ -22,6 +22,8 @@ import { WrapField } from './wrap-field';
|
|
|
22
22
|
|
|
23
23
|
export const LayoutSection = () => {
|
|
24
24
|
const [ display ] = useStylesField< StringPropValue >( 'display' );
|
|
25
|
+
const displayPlaceholder = useDisplayPlaceholderValue();
|
|
26
|
+
const isDisplayFlex = shouldDisplayFlexFields( display, displayPlaceholder as StringPropValue );
|
|
25
27
|
const { element } = useElement();
|
|
26
28
|
const parent = useParentElement( element.id );
|
|
27
29
|
const parentStyle = useComputedStyle( parent?.id || null );
|
|
@@ -29,7 +31,7 @@ export const LayoutSection = () => {
|
|
|
29
31
|
return (
|
|
30
32
|
<SectionContent>
|
|
31
33
|
<DisplayField />
|
|
32
|
-
{
|
|
34
|
+
{ isDisplayFlex && <FlexFields /> }
|
|
33
35
|
{ 'flex' === parentStyle?.display && <FlexChildFields /> }
|
|
34
36
|
</SectionContent>
|
|
35
37
|
);
|
|
@@ -60,3 +62,13 @@ const FlexChildFields = () => (
|
|
|
60
62
|
<FlexSizeField />
|
|
61
63
|
</>
|
|
62
64
|
);
|
|
65
|
+
|
|
66
|
+
const shouldDisplayFlexFields = ( display: StringPropValue | null, local: StringPropValue ) => {
|
|
67
|
+
const value = display?.value ?? local?.value;
|
|
68
|
+
|
|
69
|
+
if ( ! value ) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return 'flex' === value || 'inline-flex' === value;
|
|
74
|
+
};
|
|
@@ -6,18 +6,17 @@ import { __ } from '@wordpress/i18n';
|
|
|
6
6
|
|
|
7
7
|
import { StylesField } from '../../../controls-registry/styles-field';
|
|
8
8
|
import { ControlLabel } from '../../control-label';
|
|
9
|
-
import { RotatedIcon } from '../layout-section/utils/rotated-icon';
|
|
10
9
|
|
|
11
10
|
type Alignments = 'start' | 'center' | 'end' | 'justify';
|
|
12
11
|
|
|
13
|
-
const
|
|
14
|
-
const
|
|
12
|
+
const AlignStartIcon = withDirection( AlignLeftIcon );
|
|
13
|
+
const AlignEndIcon = withDirection( AlignRightIcon );
|
|
15
14
|
|
|
16
15
|
const options: ToggleButtonGroupItem< Alignments >[] = [
|
|
17
16
|
{
|
|
18
17
|
value: 'start',
|
|
19
18
|
label: __( 'Start', 'elementor' ),
|
|
20
|
-
renderContent: () => <
|
|
19
|
+
renderContent: ( { size } ) => <AlignStartIcon fontSize={ size } />,
|
|
21
20
|
showTooltip: true,
|
|
22
21
|
},
|
|
23
22
|
{
|
|
@@ -29,7 +28,7 @@ const options: ToggleButtonGroupItem< Alignments >[] = [
|
|
|
29
28
|
{
|
|
30
29
|
value: 'end',
|
|
31
30
|
label: __( 'End', 'elementor' ),
|
|
32
|
-
renderContent: () => <
|
|
31
|
+
renderContent: ( { size } ) => <AlignEndIcon fontSize={ size } />,
|
|
33
32
|
showTooltip: true,
|
|
34
33
|
},
|
|
35
34
|
{
|
|
@@ -45,7 +44,7 @@ export const TextAlignmentField = () => {
|
|
|
45
44
|
<StylesField bind={ 'text-align' }>
|
|
46
45
|
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
47
46
|
<Grid item xs={ 6 }>
|
|
48
|
-
<ControlLabel>{ __( '
|
|
47
|
+
<ControlLabel>{ __( 'Text align', 'elementor' ) }</ControlLabel>
|
|
49
48
|
</Grid>
|
|
50
49
|
<Grid item xs={ 6 } display="flex" justifyContent="end">
|
|
51
50
|
<ToggleControl options={ options } />
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { useState } from 'react';
|
|
3
|
-
import {
|
|
4
|
-
import { CLASSES_PROP_KEY, type ClassesPropValue, type PropKey } from '@elementor/editor-props';
|
|
3
|
+
import { CLASSES_PROP_KEY } from '@elementor/editor-props';
|
|
5
4
|
import { useActiveBreakpoint } from '@elementor/editor-responsive';
|
|
6
5
|
import { type StyleDefinitionID, type StyleDefinitionState } from '@elementor/editor-styles';
|
|
7
6
|
import { SessionStorageProvider } from '@elementor/session';
|
|
@@ -12,6 +11,7 @@ import { ClassesPropProvider } from '../contexts/classes-prop-context';
|
|
|
12
11
|
import { useElement } from '../contexts/element-context';
|
|
13
12
|
import { StyleProvider } from '../contexts/style-context';
|
|
14
13
|
import { StyleInheritanceProvider } from '../contexts/styles-inheritance-context';
|
|
14
|
+
import { useActiveStyleDefId } from '../hooks/use-active-style-def-id';
|
|
15
15
|
import { CssClassSelector } from './css-classes/css-class-selector';
|
|
16
16
|
import { Section } from './section';
|
|
17
17
|
import { SectionsList } from './sections-list';
|
|
@@ -78,23 +78,6 @@ export const StyleTab = () => {
|
|
|
78
78
|
);
|
|
79
79
|
};
|
|
80
80
|
|
|
81
|
-
function useActiveStyleDefId( currentClassesProp: PropKey ) {
|
|
82
|
-
const [ activeStyledDefId, setActiveStyledDefId ] = useState< StyleDefinitionID | null >( null );
|
|
83
|
-
|
|
84
|
-
const fallback = useFirstElementStyleDef( currentClassesProp );
|
|
85
|
-
|
|
86
|
-
return [ activeStyledDefId || fallback?.id || null, setActiveStyledDefId ] as const;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function useFirstElementStyleDef( currentClassesProp: PropKey ) {
|
|
90
|
-
const { element } = useElement();
|
|
91
|
-
|
|
92
|
-
const classesIds = useElementSetting< ClassesPropValue >( element.id, currentClassesProp )?.value || [];
|
|
93
|
-
const stylesDefs = getElementStyles( element.id ) ?? {};
|
|
94
|
-
|
|
95
|
-
return Object.values( stylesDefs ).find( ( styleDef ) => classesIds.includes( styleDef.id ) );
|
|
96
|
-
}
|
|
97
|
-
|
|
98
81
|
function useCurrentClassesProp(): string {
|
|
99
82
|
const { elementType } = useElement();
|
|
100
83
|
|
|
@@ -50,9 +50,9 @@ export function useStyle() {
|
|
|
50
50
|
return context;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
function getProviderByStyleId( styleId: StyleDefinitionID ) {
|
|
53
|
+
export function getProviderByStyleId( styleId: StyleDefinitionID ) {
|
|
54
54
|
const styleProvider = stylesRepository.getProviders().find( ( provider ) => {
|
|
55
|
-
return provider.actions.
|
|
55
|
+
return provider.actions.all().find( ( style ) => style.id === styleId );
|
|
56
56
|
} );
|
|
57
57
|
|
|
58
58
|
return styleProvider ?? null;
|
|
@@ -23,7 +23,7 @@ const StyledContainer = styled( Box, {
|
|
|
23
23
|
const getGridLayout = ( layout: ControlLayout ) => ( {
|
|
24
24
|
justifyContent: 'space-between',
|
|
25
25
|
gridTemplateColumns: {
|
|
26
|
-
full: '1fr',
|
|
27
|
-
'two-columns': 'repeat(2, 1fr)',
|
|
26
|
+
full: 'minmax(0, 1fr)',
|
|
27
|
+
'two-columns': 'repeat(2, minmax(0, 1fr))',
|
|
28
28
|
}[ layout ],
|
|
29
29
|
} );
|
|
@@ -9,10 +9,11 @@ import { createTopLevelOjectType } from './create-top-level-object-type';
|
|
|
9
9
|
|
|
10
10
|
export type StylesFieldProps = {
|
|
11
11
|
bind: PropKey;
|
|
12
|
+
placeholder?: PropValue;
|
|
12
13
|
children: React.ReactNode;
|
|
13
14
|
};
|
|
14
15
|
|
|
15
|
-
export const StylesField = ( { bind, children }: StylesFieldProps ) => {
|
|
16
|
+
export const StylesField = ( { bind, placeholder, children }: StylesFieldProps ) => {
|
|
16
17
|
const [ value, setValue ] = useStylesField( bind );
|
|
17
18
|
|
|
18
19
|
const stylesSchema = getStylesSchema();
|
|
@@ -20,6 +21,7 @@ export const StylesField = ( { bind, children }: StylesFieldProps ) => {
|
|
|
20
21
|
const propType = createTopLevelOjectType( { schema: stylesSchema } );
|
|
21
22
|
|
|
22
23
|
const values = { [ bind ]: value };
|
|
24
|
+
const placeholderValues = { [ bind ]: placeholder };
|
|
23
25
|
|
|
24
26
|
const setValues = ( newValue: Record< string, PropValue > ) => {
|
|
25
27
|
setValue( newValue[ bind ] );
|
|
@@ -34,7 +36,12 @@ export const StylesField = ( { bind, children }: StylesFieldProps ) => {
|
|
|
34
36
|
},
|
|
35
37
|
] }
|
|
36
38
|
>
|
|
37
|
-
<PropProvider
|
|
39
|
+
<PropProvider
|
|
40
|
+
propType={ propType }
|
|
41
|
+
value={ values }
|
|
42
|
+
setValue={ setValues }
|
|
43
|
+
placeholder={ placeholderValues }
|
|
44
|
+
>
|
|
38
45
|
<PropKeyProvider bind={ bind }>{ children }</PropKeyProvider>
|
|
39
46
|
</PropProvider>
|
|
40
47
|
</ControlAdornmentsProvider>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { createTransformer } from '@elementor/editor-canvas';
|
|
2
|
+
import { isTransformable, type Props } from '@elementor/editor-props';
|
|
3
|
+
|
|
4
|
+
import { DynamicTagsManagerNotFoundError } from './errors';
|
|
5
|
+
import { type ExtendedWindow } from './types';
|
|
6
|
+
|
|
7
|
+
type Dynamic = {
|
|
8
|
+
name?: string;
|
|
9
|
+
settings?: Props;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const dynamicTransformer = createTransformer( ( value: Dynamic ) => {
|
|
13
|
+
if ( ! value.name ) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return getDynamicValue( value.name, simpleTransform( value.settings ?? {} ) );
|
|
18
|
+
} );
|
|
19
|
+
|
|
20
|
+
// Temporary naive transformation until we'll have a `backendTransformer` that
|
|
21
|
+
// will replace the `dynamicTransformer` client implementation.
|
|
22
|
+
function simpleTransform( props: Props ) {
|
|
23
|
+
const transformed = Object.entries( props ).map( ( [ settingKey, settingValue ] ) => {
|
|
24
|
+
const value = isTransformable( settingValue ) ? settingValue.value : settingValue;
|
|
25
|
+
|
|
26
|
+
return [ settingKey, value ] as const;
|
|
27
|
+
} );
|
|
28
|
+
|
|
29
|
+
return Object.fromEntries( transformed );
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function getDynamicValue( name: string, settings: Record< string, unknown > ) {
|
|
33
|
+
const extendedWindow = window as unknown as ExtendedWindow;
|
|
34
|
+
const { dynamicTags } = extendedWindow.elementor ?? {};
|
|
35
|
+
|
|
36
|
+
if ( ! dynamicTags ) {
|
|
37
|
+
throw new DynamicTagsManagerNotFoundError();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const getTagValue = () => {
|
|
41
|
+
const tag = dynamicTags.createTag( 'v4-dynamic-tag', name, settings );
|
|
42
|
+
|
|
43
|
+
if ( ! tag ) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return dynamicTags.loadTagDataFromCache( tag ) ?? null;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const tagValue = getTagValue();
|
|
51
|
+
|
|
52
|
+
if ( tagValue !== null ) {
|
|
53
|
+
return tagValue;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return new Promise( ( resolve ) => {
|
|
57
|
+
dynamicTags.refreshCacheFromServer( () => {
|
|
58
|
+
resolve( getTagValue() );
|
|
59
|
+
} );
|
|
60
|
+
} );
|
|
61
|
+
}
|
package/src/dynamics/init.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { settingsTransformersRegistry, styleTransformersRegistry } from '@elementor/editor-canvas';
|
|
2
|
+
|
|
1
3
|
import { replaceControl } from '../control-replacement';
|
|
2
4
|
import { controlActionsMenu } from '../controls-actions';
|
|
3
5
|
import { DynamicSelectionControl } from './components/dynamic-selection-control';
|
|
6
|
+
import { dynamicTransformer } from './dynamic-transformer';
|
|
4
7
|
import { usePropDynamicAction } from './hooks/use-prop-dynamic-action';
|
|
5
8
|
import { isDynamicPropValue } from './utils';
|
|
6
9
|
|
|
@@ -16,4 +19,7 @@ export const init = () => {
|
|
|
16
19
|
id: 'dynamic-tags',
|
|
17
20
|
useProps: usePropDynamicAction,
|
|
18
21
|
} );
|
|
22
|
+
|
|
23
|
+
styleTransformersRegistry.register( 'dynamic', dynamicTransformer );
|
|
24
|
+
settingsTransformersRegistry.register( 'dynamic', dynamicTransformer );
|
|
19
25
|
};
|
package/src/dynamics/types.ts
CHANGED
|
@@ -9,6 +9,7 @@ export type ExtendedWindow = Window & {
|
|
|
9
9
|
groups: Record< DynamicTag[ 'group' ], { title: string } >;
|
|
10
10
|
};
|
|
11
11
|
};
|
|
12
|
+
dynamicTags?: DynamicTagsManager;
|
|
12
13
|
};
|
|
13
14
|
};
|
|
14
15
|
|
|
@@ -34,3 +35,19 @@ export type DynamicPropValue = TransformablePropValue<
|
|
|
34
35
|
'dynamic',
|
|
35
36
|
{ name: string; settings?: Record< string, unknown > }
|
|
36
37
|
>;
|
|
38
|
+
|
|
39
|
+
export type DynamicTagsManager = {
|
|
40
|
+
createTag: ( id: string, name: string, settings: Record< string, unknown > ) => TagInstance;
|
|
41
|
+
loadTagDataFromCache: ( tag: TagInstance ) => unknown;
|
|
42
|
+
refreshCacheFromServer: ( callback: () => void ) => void;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type TagInstance = {
|
|
46
|
+
options: {
|
|
47
|
+
id: string;
|
|
48
|
+
name: string;
|
|
49
|
+
};
|
|
50
|
+
model: {
|
|
51
|
+
toJSON: () => Record< string, unknown >;
|
|
52
|
+
};
|
|
53
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { getElementStyles, useElementSetting } from '@elementor/editor-elements';
|
|
3
|
+
import { type ClassesPropValue, type PropKey } from '@elementor/editor-props';
|
|
4
|
+
import { type StyleDefinitionID } from '@elementor/editor-styles';
|
|
5
|
+
|
|
6
|
+
import { useElement } from '../contexts/element-context';
|
|
7
|
+
|
|
8
|
+
export function useActiveStyleDefId( classProp: PropKey ) {
|
|
9
|
+
const [ activeStyledDefId, setActiveStyledDefId ] = useState< StyleDefinitionID | null >( null );
|
|
10
|
+
|
|
11
|
+
const appliedClassesIds = useAppliedClassesIds( classProp )?.value || [];
|
|
12
|
+
|
|
13
|
+
const fallback = useFirstAppliedClass( appliedClassesIds );
|
|
14
|
+
|
|
15
|
+
const activeAndAppliedClassId = useActiveAndAppliedClassId( activeStyledDefId, appliedClassesIds );
|
|
16
|
+
return [ activeAndAppliedClassId || fallback?.id || null, setActiveStyledDefId ] as const;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function useFirstAppliedClass( appliedClassesIds: string[] ) {
|
|
20
|
+
const { element } = useElement();
|
|
21
|
+
const stylesDefs = getElementStyles( element.id ) ?? {};
|
|
22
|
+
|
|
23
|
+
return Object.values( stylesDefs ).find( ( styleDef ) => appliedClassesIds.includes( styleDef.id ) );
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function useAppliedClassesIds( classProp: PropKey ) {
|
|
27
|
+
const { element } = useElement();
|
|
28
|
+
|
|
29
|
+
return useElementSetting< ClassesPropValue >( element.id, classProp );
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function useActiveAndAppliedClassId( id: StyleDefinitionID | null, appliedClassesIds: string[] ) {
|
|
33
|
+
const isClassApplied = !! id && appliedClassesIds.includes( id );
|
|
34
|
+
|
|
35
|
+
return isClassApplied ? id : null;
|
|
36
|
+
}
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
import type { Props } from '@elementor/editor-props';
|
|
10
10
|
import { getVariantByMeta, type StyleDefinition, type StyleDefinitionVariant } from '@elementor/editor-styles';
|
|
11
11
|
import { type StylesProvider } from '@elementor/editor-styles-repository';
|
|
12
|
-
import {
|
|
12
|
+
import { ELEMENTS_STYLES_RESERVED_LABEL } from '@elementor/editor-styles-repository';
|
|
13
13
|
import { undoable } from '@elementor/editor-v1-adapters';
|
|
14
14
|
import { __ } from '@wordpress/i18n';
|
|
15
15
|
|
|
@@ -78,10 +78,10 @@ function getProps< T extends Props >( { styleId, elementId, provider, meta, prop
|
|
|
78
78
|
return null;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
const style = provider.actions.
|
|
81
|
+
const style = provider.actions.get( styleId, { elementId } );
|
|
82
82
|
|
|
83
83
|
if ( ! style ) {
|
|
84
|
-
throw new StyleNotFoundUnderProviderError( { context: { styleId, providerKey: provider.
|
|
84
|
+
throw new StyleNotFoundUnderProviderError( { context: { styleId, providerKey: provider.getKey() } } );
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
const variant = getVariantByMeta( style, meta );
|
|
@@ -100,7 +100,7 @@ function useUndoableCreateElementStyle() {
|
|
|
100
100
|
do: ( payload: UndoableCreateElementStyleArgs ) => {
|
|
101
101
|
return createElementStyle( {
|
|
102
102
|
...payload,
|
|
103
|
-
label:
|
|
103
|
+
label: ELEMENTS_STYLES_RESERVED_LABEL,
|
|
104
104
|
} );
|
|
105
105
|
},
|
|
106
106
|
|
|
@@ -112,7 +112,7 @@ function useUndoableCreateElementStyle() {
|
|
|
112
112
|
return createElementStyle( {
|
|
113
113
|
...payload,
|
|
114
114
|
styleId,
|
|
115
|
-
label:
|
|
115
|
+
label: ELEMENTS_STYLES_RESERVED_LABEL,
|
|
116
116
|
} );
|
|
117
117
|
},
|
|
118
118
|
},
|
|
@@ -139,11 +139,11 @@ function useUndoableUpdateStyle() {
|
|
|
139
139
|
do: ( { elementId, styleId, provider, meta, props }: UndoableUpdateStyleArgs ) => {
|
|
140
140
|
if ( ! provider.actions.updateProps ) {
|
|
141
141
|
throw new StylesProviderCannotUpdatePropsError( {
|
|
142
|
-
context: { providerKey: provider.
|
|
142
|
+
context: { providerKey: provider.getKey() },
|
|
143
143
|
} );
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
const style = provider.actions.
|
|
146
|
+
const style = provider.actions.get( styleId, { elementId } );
|
|
147
147
|
|
|
148
148
|
const prevProps = getCurrentProps( style, meta );
|
|
149
149
|
|
package/src/index.ts
CHANGED
|
@@ -4,6 +4,4 @@ export { replaceControl } from './control-replacement';
|
|
|
4
4
|
export { injectIntoClassSelectorActions } from './components/css-classes/css-class-selector';
|
|
5
5
|
export { usePanelActions, usePanelStatus } from './panel';
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
init();
|
|
7
|
+
export { init } from './init';
|
package/src/init.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { init as initDynamics } from './dynamics/init';
|
|
|
8
8
|
import { panel } from './panel';
|
|
9
9
|
import { isAtomicWidgetSelected } from './sync/is-atomic-widget-selected';
|
|
10
10
|
|
|
11
|
-
export
|
|
11
|
+
export function init() {
|
|
12
12
|
registerPanel( panel );
|
|
13
13
|
blockV1Panel();
|
|
14
14
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { filterEmptyValues } from '@elementor/editor-props';
|
|
1
2
|
import { type BreakpointId, type BreakpointNode } from '@elementor/editor-responsive';
|
|
2
3
|
import { type StyleDefinitionState } from '@elementor/editor-styles';
|
|
3
4
|
|
|
@@ -10,12 +11,12 @@ import {
|
|
|
10
11
|
type StylesInheritanceSnapshot,
|
|
11
12
|
type StylesInheritanceSnapshotGetter,
|
|
12
13
|
type StylesInheritanceSnapshotsSlot,
|
|
13
|
-
type
|
|
14
|
+
type StyleVariantDetails,
|
|
14
15
|
} from './types';
|
|
15
16
|
import { DEFAULT_STATE, getBreakpointKey, getStateKey } from './utils';
|
|
16
17
|
|
|
17
18
|
export function createSnapshotsManager(
|
|
18
|
-
getStylesByMeta: ( meta: StyleInheritanceMetaProps ) =>
|
|
19
|
+
getStylesByMeta: ( meta: StyleInheritanceMetaProps ) => StyleVariantDetails[],
|
|
19
20
|
breakpointsRoot: BreakpointNode
|
|
20
21
|
): StylesInheritanceSnapshotGetter {
|
|
21
22
|
const breakpointsInheritancePaths = makeBreakpointsInheritancePaths( breakpointsRoot );
|
|
@@ -104,7 +105,7 @@ function makeBreakpointsInheritancePaths( root: BreakpointNode ): BreakpointsInh
|
|
|
104
105
|
|
|
105
106
|
// creates a snapshot slot for a specific breakpoint and state
|
|
106
107
|
function buildStateSnapshotSlot(
|
|
107
|
-
styles:
|
|
108
|
+
styles: StyleVariantDetails[],
|
|
108
109
|
parentBreakpoint: BreakpointStatesSlotsMapping | undefined,
|
|
109
110
|
currentBreakpoint: BreakpointStatesSlotsMapping,
|
|
110
111
|
state: StyleDefinitionState
|
|
@@ -132,22 +133,28 @@ function buildStateSnapshotSlot(
|
|
|
132
133
|
}
|
|
133
134
|
|
|
134
135
|
// creates an initial snapshot based on the passed style variants only
|
|
135
|
-
function buildInitialSnapshotFromStyles( styles:
|
|
136
|
+
function buildInitialSnapshotFromStyles( styles: StyleVariantDetails[] ): StylesInheritanceSnapshotsSlot {
|
|
136
137
|
const snapshot: StylesInheritanceSnapshot = {};
|
|
137
138
|
|
|
138
|
-
styles.forEach( (
|
|
139
|
+
styles.forEach( ( styleData ) => {
|
|
139
140
|
const {
|
|
140
|
-
|
|
141
|
-
} =
|
|
141
|
+
variant: { props },
|
|
142
|
+
} = styleData;
|
|
142
143
|
|
|
143
144
|
Object.entries( props ).forEach( ( [ key, value ] ) => {
|
|
145
|
+
const filteredValue = filterEmptyValues( value );
|
|
146
|
+
|
|
147
|
+
if ( filteredValue === null ) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
144
151
|
if ( ! snapshot[ key ] ) {
|
|
145
152
|
snapshot[ key ] = [];
|
|
146
153
|
}
|
|
147
154
|
|
|
148
155
|
const snapshotPropValue: SnapshotPropValue = {
|
|
149
|
-
...
|
|
150
|
-
value,
|
|
156
|
+
...styleData,
|
|
157
|
+
value: filteredValue,
|
|
151
158
|
};
|
|
152
159
|
|
|
153
160
|
snapshot[ key ].push( snapshotPropValue );
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type BreakpointNode } from '@elementor/editor-responsive';
|
|
2
2
|
import { type StyleDefinition } from '@elementor/editor-styles';
|
|
3
3
|
|
|
4
|
+
import { getProviderByStyleId } from '../contexts/style-context';
|
|
4
5
|
import { createSnapshotsManager } from './create-snapshots-manager';
|
|
5
6
|
import { type BreakpointsStatesStyles, type StyleInheritanceMetaProps, type StylesInheritanceSnapshot } from './types';
|
|
6
7
|
import { getBreakpointKey, getStateKey } from './utils';
|
|
@@ -21,9 +22,11 @@ function buildStyleVariantsByMetaMapping( styleDefs: StyleDefinition[] ): Breakp
|
|
|
21
22
|
const breakpointStateSlots: BreakpointsStatesStyles = {};
|
|
22
23
|
|
|
23
24
|
styleDefs.forEach( ( styleDef ) => {
|
|
25
|
+
const provider = getProviderByStyleId( styleDef.id )?.getKey() ?? null;
|
|
26
|
+
|
|
24
27
|
// iterate over each style definition's variants and place them in the corresponding breakpoint's base or state styles
|
|
25
|
-
styleDef.variants.forEach( (
|
|
26
|
-
const { meta } =
|
|
28
|
+
styleDef.variants.forEach( ( variant ) => {
|
|
29
|
+
const { meta } = variant;
|
|
27
30
|
const { state, breakpoint } = meta;
|
|
28
31
|
|
|
29
32
|
const breakpointKey = getBreakpointKey( breakpoint );
|
|
@@ -40,8 +43,9 @@ function buildStyleVariantsByMetaMapping( styleDefs: StyleDefinition[] ): Breakp
|
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
breakpointNode[ stateKey ].push( {
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
style: styleDef,
|
|
47
|
+
variant,
|
|
48
|
+
provider,
|
|
45
49
|
} );
|
|
46
50
|
} );
|
|
47
51
|
} );
|