@elementor/editor-editing-panel 3.33.0-99 → 3.34.3
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.d.mts +419 -88
- package/dist/index.d.ts +419 -88
- package/dist/index.js +3361 -2421
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3299 -2347
- package/dist/index.mjs.map +1 -1
- package/package.json +22 -21
- package/src/apply-unapply-actions.ts +30 -0
- package/src/components/collapsible-content.tsx +1 -0
- package/src/components/css-classes/css-class-item.tsx +14 -4
- package/src/components/css-classes/css-class-menu.tsx +83 -11
- package/src/components/css-classes/css-class-selector.tsx +22 -1
- package/src/components/css-classes/use-apply-and-unapply-class.ts +4 -13
- package/src/components/custom-css-indicator.tsx +68 -1
- package/src/components/editing-panel-tabs.tsx +13 -2
- package/src/components/interactions-tab.tsx +15 -0
- package/src/components/section-content.tsx +3 -2
- package/src/components/section.tsx +2 -1
- package/src/components/settings-control.tsx +79 -0
- package/src/components/settings-tab.tsx +16 -46
- package/src/components/style-sections/border-section/border-section.tsx +6 -4
- package/src/components/style-sections/effects-section/blend-mode-field.tsx +44 -0
- package/src/components/style-sections/effects-section/effects-section.tsx +4 -1
- package/src/components/style-sections/layout-section/flex-size-field.tsx +10 -8
- package/src/components/style-sections/typography-section/font-family-field.tsx +5 -1
- package/src/components/style-sections/typography-section/font-size-field.tsx +1 -1
- package/src/components/style-sections/typography-section/letter-spacing-field.tsx +1 -1
- package/src/components/style-sections/typography-section/text-color-field.tsx +1 -1
- package/src/components/style-sections/typography-section/word-spacing-field.tsx +1 -1
- package/src/components/style-tab-section.tsx +2 -2
- package/src/components/style-tab.tsx +12 -17
- package/src/components/styles-field-layout.tsx +8 -1
- package/src/contexts/interaction-context.tsx +0 -0
- package/src/controls-registry/conditional-field.tsx +1 -1
- package/src/controls-registry/control-type-container.tsx +17 -5
- package/src/controls-registry/controls-registry.tsx +18 -5
- package/src/controls-registry/element-controls/get-element-by-type.ts +21 -0
- package/src/controls-registry/element-controls/registry.ts +16 -0
- package/src/controls-registry/element-controls/tabs-control/tabs-control.tsx +229 -0
- package/src/controls-registry/element-controls/tabs-control/use-actions.ts +248 -0
- package/src/controls-registry/settings-field.tsx +54 -10
- package/src/controls-registry/styles-field.tsx +2 -9
- package/src/dynamics/components/dynamic-conditional-control.tsx +62 -0
- package/src/dynamics/components/dynamic-selection-control.tsx +81 -25
- package/src/dynamics/components/dynamic-selection.tsx +3 -3
- package/src/dynamics/dynamic-control.tsx +10 -1
- package/src/dynamics/hooks/use-prop-dynamic-tags.ts +24 -6
- package/src/field-indicators-registry.ts +37 -0
- package/src/hooks/use-computed-style.ts +1 -4
- package/src/index.ts +16 -3
- package/src/init.ts +7 -0
- package/src/reset-style-props.tsx +21 -4
- package/src/styles-inheritance/components/infotip/value-component.tsx +2 -0
- package/src/styles-inheritance/components/styles-inheritance-indicator.tsx +1 -13
- package/src/styles-inheritance/components/styles-inheritance-infotip.tsx +5 -1
- package/src/styles-inheritance/hooks/use-normalized-inheritance-chain-items.tsx +18 -2
- package/src/styles-inheritance/init-styles-inheritance-transformers.ts +25 -4
- package/src/styles-inheritance/init.ts +9 -0
- package/src/styles-inheritance/transformers/{background-overlay-transformer.tsx → array-transformer.tsx} +2 -2
- package/src/styles-inheritance/transformers/background-color-overlay-transformer.tsx +0 -6
- package/src/styles-inheritance/transformers/box-shadow-transformer.tsx +32 -0
- package/src/styles-inheritance/transformers/color-transformer.tsx +32 -0
- package/src/styles-inheritance/transformers/repeater-to-items-transformer.tsx +27 -0
- package/src/utils/is-equal.ts +53 -0
- package/src/utils/prop-dependency-utils.ts +107 -19
- package/src/utils/tracking/subscribe.ts +7 -0
- package/src/components/custom-css-field.tsx +0 -20
- package/src/components/custom-css.tsx +0 -36
- package/src/components/style-sections/border-section/border-field.tsx +0 -54
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ControlAdornmentsProvider } from '@elementor/editor-controls';
|
|
3
|
+
import { type Control, type ControlLayout, type ElementControl } from '@elementor/editor-elements';
|
|
4
|
+
import { Divider, styled } from '@elementor/ui';
|
|
5
|
+
|
|
6
|
+
import { Control as BaseControl } from '../controls-registry/control';
|
|
7
|
+
import { ControlTypeContainer } from '../controls-registry/control-type-container';
|
|
8
|
+
import { controlsRegistry, type ControlType } from '../controls-registry/controls-registry';
|
|
9
|
+
import { SettingsField } from '../controls-registry/settings-field';
|
|
10
|
+
import { getFieldIndicators } from '../field-indicators-registry';
|
|
11
|
+
import { ControlLabel } from './control-label';
|
|
12
|
+
|
|
13
|
+
const Wrapper = styled( 'span' )`
|
|
14
|
+
display: contents;
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
export const SettingsControl = ( { control: { value, type } }: { control: Control | ElementControl } ) => {
|
|
18
|
+
if ( ! controlsRegistry.get( value.type as ControlType ) ) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const layout = value.meta?.layout || controlsRegistry.getLayout( value.type as ControlType );
|
|
23
|
+
const controlProps = populateChildControlProps( value.props );
|
|
24
|
+
|
|
25
|
+
if ( layout === 'custom' ) {
|
|
26
|
+
controlProps.label = value.label;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if ( type === 'element-control' ) {
|
|
30
|
+
return <ControlLayout control={ value } layout={ layout } controlProps={ controlProps } />;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<SettingsField bind={ value.bind } propDisplayName={ value.label || value.bind }>
|
|
35
|
+
<ControlLayout control={ value } layout={ layout } controlProps={ controlProps } />
|
|
36
|
+
</SettingsField>
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const ControlLayout = ( {
|
|
41
|
+
control,
|
|
42
|
+
layout,
|
|
43
|
+
controlProps,
|
|
44
|
+
}: {
|
|
45
|
+
control: Control[ 'value' ] | ElementControl[ 'value' ];
|
|
46
|
+
layout: ControlLayout;
|
|
47
|
+
controlProps: Record< string, unknown >;
|
|
48
|
+
} ) => {
|
|
49
|
+
const controlType = control.type as ControlType;
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<ControlAdornmentsProvider items={ getFieldIndicators( 'settings' ) }>
|
|
53
|
+
{ control.meta?.topDivider && <Divider /> }
|
|
54
|
+
<Wrapper data-type="settings-field">
|
|
55
|
+
<ControlTypeContainer layout={ layout }>
|
|
56
|
+
{ control.label && layout !== 'custom' ? <ControlLabel>{ control.label }</ControlLabel> : null }
|
|
57
|
+
<BaseControl type={ controlType } props={ controlProps } />
|
|
58
|
+
</ControlTypeContainer>
|
|
59
|
+
</Wrapper>
|
|
60
|
+
</ControlAdornmentsProvider>
|
|
61
|
+
);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
function populateChildControlProps( props: Record< string, unknown > ) {
|
|
65
|
+
if ( props.childControlType ) {
|
|
66
|
+
const childComponent = controlsRegistry.get( props.childControlType as ControlType );
|
|
67
|
+
const childPropType = controlsRegistry.getPropTypeUtil( props.childControlType as ControlType );
|
|
68
|
+
props = {
|
|
69
|
+
...props,
|
|
70
|
+
childControlConfig: {
|
|
71
|
+
component: childComponent,
|
|
72
|
+
props: props.childControlProps || {},
|
|
73
|
+
propTypeUtil: childPropType,
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return props;
|
|
79
|
+
}
|
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import { type Control } from '@elementor/editor-elements';
|
|
2
|
+
import { type Control, type ControlItem, type Element, type ElementControl } from '@elementor/editor-elements';
|
|
4
3
|
import { SessionStorageProvider } from '@elementor/session';
|
|
5
|
-
import { Divider } from '@elementor/ui';
|
|
6
4
|
|
|
7
5
|
import { useElement } from '../contexts/element-context';
|
|
8
|
-
import { Control as BaseControl } from '../controls-registry/control';
|
|
9
|
-
import { ControlTypeContainer } from '../controls-registry/control-type-container';
|
|
10
|
-
import { controlsRegistry, type ControlType } from '../controls-registry/controls-registry';
|
|
11
|
-
import { SettingsField } from '../controls-registry/settings-field';
|
|
12
6
|
import { useDefaultPanelSettings } from '../hooks/use-default-panel-settings';
|
|
13
7
|
import { Section } from './section';
|
|
14
8
|
import { SectionsList } from './sections-list';
|
|
9
|
+
import { SettingsControl } from './settings-control';
|
|
15
10
|
|
|
16
11
|
export const SettingsTab = () => {
|
|
17
12
|
const { elementType, element } = useElement();
|
|
@@ -23,11 +18,13 @@ export const SettingsTab = () => {
|
|
|
23
18
|
return (
|
|
24
19
|
<SessionStorageProvider prefix={ element.id }>
|
|
25
20
|
<SectionsList>
|
|
26
|
-
{ elementType.controls.map( (
|
|
27
|
-
if (
|
|
28
|
-
return <
|
|
21
|
+
{ elementType.controls.map( ( control, index ) => {
|
|
22
|
+
if ( isControl( control ) ) {
|
|
23
|
+
return <SettingsControl key={ getKey( control, element ) } control={ control } />;
|
|
29
24
|
}
|
|
30
25
|
|
|
26
|
+
const { type, value } = control;
|
|
27
|
+
|
|
31
28
|
if ( type === 'section' ) {
|
|
32
29
|
return (
|
|
33
30
|
<Section
|
|
@@ -36,8 +33,8 @@ export const SettingsTab = () => {
|
|
|
36
33
|
defaultExpanded={ isDefaultExpanded( value.label ) }
|
|
37
34
|
>
|
|
38
35
|
{ value.items?.map( ( item ) => {
|
|
39
|
-
if ( item
|
|
40
|
-
return <
|
|
36
|
+
if ( isControl( item ) ) {
|
|
37
|
+
return <SettingsControl key={ getKey( item, element ) } control={ item } />;
|
|
41
38
|
}
|
|
42
39
|
|
|
43
40
|
// TODO: Handle 2nd level sections
|
|
@@ -54,41 +51,14 @@ export const SettingsTab = () => {
|
|
|
54
51
|
);
|
|
55
52
|
};
|
|
56
53
|
|
|
57
|
-
|
|
58
|
-
if (
|
|
59
|
-
return
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const layout = control.meta?.layout || controlsRegistry.getLayout( control.type as ControlType );
|
|
63
|
-
const controlProps = populateChildControlProps( control.props );
|
|
64
|
-
if ( layout === 'custom' ) {
|
|
65
|
-
controlProps.label = control.label;
|
|
54
|
+
function getKey( control: Control | ElementControl, element: Element ) {
|
|
55
|
+
if ( control.type === 'control' ) {
|
|
56
|
+
return control.value.bind + '.' + element.id;
|
|
66
57
|
}
|
|
67
58
|
|
|
68
|
-
return
|
|
69
|
-
|
|
70
|
-
{ control.meta?.topDivider && <Divider /> }
|
|
71
|
-
<ControlTypeContainer layout={ layout }>
|
|
72
|
-
{ control.label && layout !== 'custom' ? <ControlFormLabel>{ control.label }</ControlFormLabel> : null }
|
|
73
|
-
<BaseControl type={ control.type as ControlType } props={ controlProps } />
|
|
74
|
-
</ControlTypeContainer>
|
|
75
|
-
</SettingsField>
|
|
76
|
-
);
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
function populateChildControlProps( props: Record< string, unknown > ) {
|
|
80
|
-
if ( props.childControlType ) {
|
|
81
|
-
const childComponent = controlsRegistry.get( props.childControlType as ControlType );
|
|
82
|
-
const childPropType = controlsRegistry.getPropTypeUtil( props.childControlType as ControlType );
|
|
83
|
-
props = {
|
|
84
|
-
...props,
|
|
85
|
-
childControlConfig: {
|
|
86
|
-
component: childComponent,
|
|
87
|
-
props: props.childControlProps || {},
|
|
88
|
-
propTypeUtil: childPropType,
|
|
89
|
-
},
|
|
90
|
-
};
|
|
91
|
-
}
|
|
59
|
+
return control.value.type + '.' + element.id;
|
|
60
|
+
}
|
|
92
61
|
|
|
93
|
-
|
|
62
|
+
function isControl( control: ControlItem ): control is Control | ElementControl {
|
|
63
|
+
return control.type === 'control' || control.type === 'element-control';
|
|
94
64
|
}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
-
import { PanelDivider } from '../../panel-divider';
|
|
4
3
|
import { SectionContent } from '../../section-content';
|
|
5
|
-
import {
|
|
4
|
+
import { BorderColorField } from './border-color-field';
|
|
6
5
|
import { BorderRadiusField } from './border-radius-field';
|
|
6
|
+
import { BorderStyleField } from './border-style-field';
|
|
7
|
+
import { BorderWidthField } from './border-width-field';
|
|
7
8
|
|
|
8
9
|
export const BorderSection = () => (
|
|
9
10
|
<SectionContent>
|
|
11
|
+
<BorderWidthField />
|
|
12
|
+
<BorderColorField />
|
|
13
|
+
<BorderStyleField />
|
|
10
14
|
<BorderRadiusField />
|
|
11
|
-
<PanelDivider />
|
|
12
|
-
<BorderField />
|
|
13
15
|
</SectionContent>
|
|
14
16
|
);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { SelectControl } from '@elementor/editor-controls';
|
|
3
|
+
import { __ } from '@wordpress/i18n';
|
|
4
|
+
|
|
5
|
+
import { StylesField } from '../../../controls-registry/styles-field';
|
|
6
|
+
import { StylesFieldLayout } from '../../styles-field-layout';
|
|
7
|
+
|
|
8
|
+
const BLEND_MODE_LABEL = __( 'Blend mode', 'elementor' );
|
|
9
|
+
|
|
10
|
+
const blendModeOptions = [
|
|
11
|
+
{ label: __( 'Normal', 'elementor' ), value: 'normal' },
|
|
12
|
+
{ label: __( 'Multiply', 'elementor' ), value: 'multiply' },
|
|
13
|
+
{ label: __( 'Screen', 'elementor' ), value: 'screen' },
|
|
14
|
+
{ label: __( 'Overlay', 'elementor' ), value: 'overlay' },
|
|
15
|
+
{ label: __( 'Darken', 'elementor' ), value: 'darken' },
|
|
16
|
+
{ label: __( 'Lighten', 'elementor' ), value: 'lighten' },
|
|
17
|
+
{ label: __( 'Color dodge', 'elementor' ), value: 'color-dodge' },
|
|
18
|
+
{ label: __( 'Color burn', 'elementor' ), value: 'color-burn' },
|
|
19
|
+
{ label: __( 'Saturation', 'elementor' ), value: 'saturation' },
|
|
20
|
+
{ label: __( 'Color', 'elementor' ), value: 'color' },
|
|
21
|
+
{ label: __( 'Difference', 'elementor' ), value: 'difference' },
|
|
22
|
+
{ label: __( 'Exclusion', 'elementor' ), value: 'exclusion' },
|
|
23
|
+
{ label: __( 'Hue', 'elementor' ), value: 'hue' },
|
|
24
|
+
{ label: __( 'Luminosity', 'elementor' ), value: 'luminosity' },
|
|
25
|
+
{ label: __( 'Soft light', 'elementor' ), value: 'soft-light' },
|
|
26
|
+
{ label: __( 'Hard light', 'elementor' ), value: 'hard-light' },
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
export const BlendModeField = () => {
|
|
30
|
+
return (
|
|
31
|
+
<StylesField bind="mix-blend-mode" propDisplayName={ BLEND_MODE_LABEL }>
|
|
32
|
+
<StylesFieldLayout label={ BLEND_MODE_LABEL }>
|
|
33
|
+
<SelectControl
|
|
34
|
+
options={ blendModeOptions }
|
|
35
|
+
MenuProps={ {
|
|
36
|
+
sx: {
|
|
37
|
+
maxHeight: '256px',
|
|
38
|
+
},
|
|
39
|
+
} }
|
|
40
|
+
/>
|
|
41
|
+
</StylesFieldLayout>
|
|
42
|
+
</StylesField>
|
|
43
|
+
);
|
|
44
|
+
};
|
|
@@ -13,6 +13,7 @@ import { StylesField } from '../../../controls-registry/styles-field';
|
|
|
13
13
|
import { getRecentlyUsedList } from '../../../utils/get-recently-used-styles';
|
|
14
14
|
import { PanelDivider } from '../../panel-divider';
|
|
15
15
|
import { SectionContent } from '../../section-content';
|
|
16
|
+
import { BlendModeField } from './blend-mode-field';
|
|
16
17
|
import { OpacityControlField } from './opacity-control-field';
|
|
17
18
|
|
|
18
19
|
const BOX_SHADOW_LABEL = __( 'Box shadow', 'elementor' );
|
|
@@ -26,7 +27,9 @@ export const EffectsSection = () => {
|
|
|
26
27
|
const { meta } = useStyle();
|
|
27
28
|
|
|
28
29
|
return (
|
|
29
|
-
<SectionContent>
|
|
30
|
+
<SectionContent gap={ 1 }>
|
|
31
|
+
<BlendModeField />
|
|
32
|
+
<PanelDivider />
|
|
30
33
|
<OpacityControlField />
|
|
31
34
|
<PanelDivider />
|
|
32
35
|
<StylesField bind="box-shadow" propDisplayName={ BOX_SHADOW_LABEL }>
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
type ToggleButtonGroupItem,
|
|
10
10
|
useBoundProp,
|
|
11
11
|
} from '@elementor/editor-controls';
|
|
12
|
-
import { flexPropTypeUtil, type FlexPropValue, numberPropTypeUtil } from '@elementor/editor-props';
|
|
12
|
+
import { flexPropTypeUtil, type FlexPropValue, numberPropTypeUtil, sizePropTypeUtil } from '@elementor/editor-props';
|
|
13
13
|
import { ExpandIcon, PencilIcon, ShrinkIcon } from '@elementor/icons';
|
|
14
14
|
import { __ } from '@wordpress/i18n';
|
|
15
15
|
|
|
@@ -130,16 +130,16 @@ const createFlexValueForGroup = ( group: GroupItem | null, flexValue: FlexPropVa
|
|
|
130
130
|
if ( group === 'flex-grow' ) {
|
|
131
131
|
return flexPropTypeUtil.create( {
|
|
132
132
|
flexGrow: numberPropTypeUtil.create( DEFAULT ),
|
|
133
|
-
flexShrink:
|
|
134
|
-
flexBasis:
|
|
133
|
+
flexShrink: numberPropTypeUtil.create( 0 ),
|
|
134
|
+
flexBasis: sizePropTypeUtil.create( { unit: 'auto', size: '' } ),
|
|
135
135
|
} );
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
if ( group === 'flex-shrink' ) {
|
|
139
139
|
return flexPropTypeUtil.create( {
|
|
140
|
-
flexGrow:
|
|
140
|
+
flexGrow: numberPropTypeUtil.create( 0 ),
|
|
141
141
|
flexShrink: numberPropTypeUtil.create( DEFAULT ),
|
|
142
|
-
flexBasis:
|
|
142
|
+
flexBasis: sizePropTypeUtil.create( { unit: 'auto', size: '' } ),
|
|
143
143
|
} );
|
|
144
144
|
}
|
|
145
145
|
|
|
@@ -197,15 +197,17 @@ const getActiveGroup = ( {
|
|
|
197
197
|
return null;
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
-
|
|
200
|
+
const isAutoBasis = basis === null || ( typeof basis === 'object' && basis.unit === 'auto' );
|
|
201
|
+
|
|
202
|
+
if ( basis && ! isAutoBasis ) {
|
|
201
203
|
return 'custom';
|
|
202
204
|
}
|
|
203
205
|
|
|
204
|
-
if ( grow === DEFAULT ) {
|
|
206
|
+
if ( grow === DEFAULT && ( shrink === null || shrink === 0 ) && isAutoBasis ) {
|
|
205
207
|
return 'flex-grow';
|
|
206
208
|
}
|
|
207
209
|
|
|
208
|
-
if ( shrink === DEFAULT ) {
|
|
210
|
+
if ( shrink === DEFAULT && ( grow === null || grow === 0 ) && isAutoBasis ) {
|
|
209
211
|
return 'flex-shrink';
|
|
210
212
|
}
|
|
211
213
|
|
|
@@ -20,7 +20,11 @@ export const FontFamilyField = () => {
|
|
|
20
20
|
return (
|
|
21
21
|
<StylesField bind="font-family" propDisplayName={ FONT_FAMILY_LABEL }>
|
|
22
22
|
<StylesFieldLayout label={ FONT_FAMILY_LABEL }>
|
|
23
|
-
<FontFamilyControl
|
|
23
|
+
<FontFamilyControl
|
|
24
|
+
fontFamilies={ fontFamilies }
|
|
25
|
+
sectionWidth={ sectionWidth }
|
|
26
|
+
ariaLabel={ FONT_FAMILY_LABEL }
|
|
27
|
+
/>
|
|
24
28
|
</StylesFieldLayout>
|
|
25
29
|
</StylesField>
|
|
26
30
|
);
|
|
@@ -14,7 +14,7 @@ export const FontSizeField = () => {
|
|
|
14
14
|
return (
|
|
15
15
|
<StylesField bind="font-size" propDisplayName={ FONT_SIZE_LABEL }>
|
|
16
16
|
<StylesFieldLayout label={ FONT_SIZE_LABEL } ref={ rowRef }>
|
|
17
|
-
<SizeControl anchorRef={ rowRef } />
|
|
17
|
+
<SizeControl anchorRef={ rowRef } ariaLabel={ FONT_SIZE_LABEL } />
|
|
18
18
|
</StylesFieldLayout>
|
|
19
19
|
</StylesField>
|
|
20
20
|
);
|
|
@@ -14,7 +14,7 @@ export const LetterSpacingField = () => {
|
|
|
14
14
|
return (
|
|
15
15
|
<StylesField bind="letter-spacing" propDisplayName={ LETTER_SPACING_LABEL }>
|
|
16
16
|
<StylesFieldLayout label={ LETTER_SPACING_LABEL } ref={ rowRef }>
|
|
17
|
-
<SizeControl anchorRef={ rowRef } />
|
|
17
|
+
<SizeControl anchorRef={ rowRef } min={ -Number.MAX_SAFE_INTEGER } />
|
|
18
18
|
</StylesFieldLayout>
|
|
19
19
|
</StylesField>
|
|
20
20
|
);
|
|
@@ -11,7 +11,7 @@ export const TextColorField = () => {
|
|
|
11
11
|
return (
|
|
12
12
|
<StylesField bind="color" propDisplayName={ TEXT_COLOR_LABEL }>
|
|
13
13
|
<StylesFieldLayout label={ TEXT_COLOR_LABEL }>
|
|
14
|
-
<ColorControl />
|
|
14
|
+
<ColorControl id="text-color-control" />
|
|
15
15
|
</StylesFieldLayout>
|
|
16
16
|
</StylesField>
|
|
17
17
|
);
|
|
@@ -14,7 +14,7 @@ export const WordSpacingField = () => {
|
|
|
14
14
|
return (
|
|
15
15
|
<StylesField bind="word-spacing" propDisplayName={ WORD_SPACING_LABEL }>
|
|
16
16
|
<StylesFieldLayout label={ WORD_SPACING_LABEL } ref={ rowRef }>
|
|
17
|
-
<SizeControl anchorRef={ rowRef } />
|
|
17
|
+
<SizeControl anchorRef={ rowRef } min={ -Number.MAX_SAFE_INTEGER } />
|
|
18
18
|
</StylesFieldLayout>
|
|
19
19
|
</StylesField>
|
|
20
20
|
);
|
|
@@ -4,13 +4,13 @@ import { useDefaultPanelSettings } from '../hooks/use-default-panel-settings';
|
|
|
4
4
|
import { Section } from './section';
|
|
5
5
|
import { getStylesInheritanceIndicators } from './style-tab-collapsible-content';
|
|
6
6
|
|
|
7
|
-
type
|
|
7
|
+
type SectionType = {
|
|
8
8
|
component: () => React.JSX.Element;
|
|
9
9
|
name: string;
|
|
10
10
|
title: string;
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
type Props = { section:
|
|
13
|
+
type Props = { section: SectionType; fields?: string[]; unmountOnExit?: boolean };
|
|
14
14
|
|
|
15
15
|
export const StyleTabSection = ( { section, fields = [], unmountOnExit = true }: Props ) => {
|
|
16
16
|
const { component, name, title } = section;
|
|
@@ -3,7 +3,7 @@ import { useState } from 'react';
|
|
|
3
3
|
import { CLASSES_PROP_KEY } from '@elementor/editor-props';
|
|
4
4
|
import { useActiveBreakpoint } from '@elementor/editor-responsive';
|
|
5
5
|
import { type StyleDefinitionID, type StyleDefinitionState } from '@elementor/editor-styles';
|
|
6
|
-
import {
|
|
6
|
+
import { createLocation } from '@elementor/locations';
|
|
7
7
|
import { SessionStorageProvider } from '@elementor/session';
|
|
8
8
|
import { Box, Divider, Stack } from '@elementor/ui';
|
|
9
9
|
import { __ } from '@wordpress/i18n';
|
|
@@ -15,7 +15,6 @@ import { StyleProvider } from '../contexts/style-context';
|
|
|
15
15
|
import { StyleInheritanceProvider } from '../contexts/styles-inheritance-context';
|
|
16
16
|
import { useActiveStyleDefId } from '../hooks/use-active-style-def-id';
|
|
17
17
|
import { CssClassSelector } from './css-classes/css-class-selector';
|
|
18
|
-
import { CustomCss } from './custom-css';
|
|
19
18
|
import { SectionsList } from './sections-list';
|
|
20
19
|
import { BackgroundSection } from './style-sections/background-section/background-section';
|
|
21
20
|
import { BorderSection } from './style-sections/border-section/border-section';
|
|
@@ -29,6 +28,8 @@ import { StyleTabSection } from './style-tab-section';
|
|
|
29
28
|
|
|
30
29
|
const TABS_HEADER_HEIGHT = '37px';
|
|
31
30
|
|
|
31
|
+
export const { Slot: StyleTabSlot, inject: injectIntoStyleTab } = createLocation();
|
|
32
|
+
|
|
32
33
|
export const stickyHeaderStyles = {
|
|
33
34
|
position: 'sticky',
|
|
34
35
|
zIndex: 1100,
|
|
@@ -39,10 +40,13 @@ export const stickyHeaderStyles = {
|
|
|
39
40
|
|
|
40
41
|
export const StyleTab = () => {
|
|
41
42
|
const currentClassesProp = useCurrentClassesProp();
|
|
42
|
-
const [ activeStyleDefId, setActiveStyleDefId ] = useActiveStyleDefId( currentClassesProp );
|
|
43
|
+
const [ activeStyleDefId, setActiveStyleDefId ] = useActiveStyleDefId( currentClassesProp ?? '' );
|
|
43
44
|
const [ activeStyleState, setActiveStyleState ] = useState< StyleDefinitionState | null >( null );
|
|
44
45
|
const breakpoint = useActiveBreakpoint();
|
|
45
|
-
|
|
46
|
+
|
|
47
|
+
if ( ! currentClassesProp ) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
46
50
|
|
|
47
51
|
return (
|
|
48
52
|
<ClassesPropProvider prop={ currentClassesProp }>
|
|
@@ -159,6 +163,7 @@ export const StyleTab = () => {
|
|
|
159
163
|
title: __( 'Effects', 'elementor' ),
|
|
160
164
|
} }
|
|
161
165
|
fields={ [
|
|
166
|
+
'mix-blend-mode',
|
|
162
167
|
'box-shadow',
|
|
163
168
|
'opacity',
|
|
164
169
|
'transform',
|
|
@@ -168,17 +173,7 @@ export const StyleTab = () => {
|
|
|
168
173
|
'transition',
|
|
169
174
|
] }
|
|
170
175
|
/>
|
|
171
|
-
|
|
172
|
-
<StyleTabSection
|
|
173
|
-
section={ {
|
|
174
|
-
component: CustomCss,
|
|
175
|
-
name: 'Custom CSS',
|
|
176
|
-
title: __( 'Custom CSS', 'elementor' ),
|
|
177
|
-
} }
|
|
178
|
-
fields={ [ 'custom_css' ] }
|
|
179
|
-
unmountOnExit={ false }
|
|
180
|
-
/>
|
|
181
|
-
) }
|
|
176
|
+
<StyleTabSlot />
|
|
182
177
|
</SectionsList>
|
|
183
178
|
<Box sx={ { height: '150px' } } />
|
|
184
179
|
</StyleInheritanceProvider>
|
|
@@ -198,7 +193,7 @@ function ClassesHeader( { children }: { children: React.ReactNode } ) {
|
|
|
198
193
|
);
|
|
199
194
|
}
|
|
200
195
|
|
|
201
|
-
function useCurrentClassesProp(): string {
|
|
196
|
+
function useCurrentClassesProp(): string | null {
|
|
202
197
|
const { elementType } = useElement();
|
|
203
198
|
|
|
204
199
|
const prop = Object.entries( elementType.propsSchema ).find(
|
|
@@ -206,7 +201,7 @@ function useCurrentClassesProp(): string {
|
|
|
206
201
|
);
|
|
207
202
|
|
|
208
203
|
if ( ! prop ) {
|
|
209
|
-
|
|
204
|
+
return null;
|
|
210
205
|
}
|
|
211
206
|
|
|
212
207
|
return prop[ 0 ];
|
|
@@ -20,7 +20,14 @@ export const StylesFieldLayout = React.forwardRef< HTMLDivElement, StylesFieldLa
|
|
|
20
20
|
const Row = React.forwardRef< HTMLDivElement, { label: string; children: React.ReactNode } >(
|
|
21
21
|
( { label, children }, ref ) => {
|
|
22
22
|
return (
|
|
23
|
-
<Grid
|
|
23
|
+
<Grid
|
|
24
|
+
container
|
|
25
|
+
gap={ 2 }
|
|
26
|
+
alignItems="center"
|
|
27
|
+
flexWrap="nowrap"
|
|
28
|
+
ref={ ref }
|
|
29
|
+
aria-label={ `${ label } control` }
|
|
30
|
+
>
|
|
24
31
|
<Grid item xs={ 6 }>
|
|
25
32
|
<ControlLabel>{ label }</ControlLabel>
|
|
26
33
|
</Grid>
|
|
File without changes
|
|
@@ -12,7 +12,7 @@ export const ConditionalField: React.FC< {
|
|
|
12
12
|
|
|
13
13
|
const { values: depValues } = useStylesFields( depList );
|
|
14
14
|
|
|
15
|
-
const isHidden = ! isDependencyMet( propType?.dependencies, depValues );
|
|
15
|
+
const isHidden = ! isDependencyMet( propType?.dependencies, depValues ).isMet;
|
|
16
16
|
|
|
17
17
|
return isHidden ? null : children;
|
|
18
18
|
};
|
|
@@ -18,10 +18,22 @@ const StyledContainer = styled( Box, {
|
|
|
18
18
|
...getGridLayout( layout ),
|
|
19
19
|
} ) );
|
|
20
20
|
|
|
21
|
-
const getGridLayout = ( layout:
|
|
21
|
+
const getGridLayout = ( layout: ControlLayout ) => ( {
|
|
22
22
|
justifyContent: 'space-between',
|
|
23
|
-
|
|
24
|
-
full: 'minmax(0, 1fr)',
|
|
25
|
-
'two-columns': 'repeat(2, minmax(0, 1fr))',
|
|
26
|
-
}[ layout as string ],
|
|
23
|
+
...getStyleByLayout( layout ),
|
|
27
24
|
} );
|
|
25
|
+
|
|
26
|
+
const getStyleByLayout = ( layout: ControlLayout ) => {
|
|
27
|
+
if ( layout === 'full' ) {
|
|
28
|
+
return {
|
|
29
|
+
gridTemplateColumns: 'minmax(0, 1fr)',
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if ( layout === 'two-columns' ) {
|
|
34
|
+
return {
|
|
35
|
+
alignItems: 'center',
|
|
36
|
+
gridTemplateColumns: 'repeat(2, minmax(0, 1fr))',
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
};
|
|
@@ -1,34 +1,42 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type ControlComponent,
|
|
3
|
+
DateTimeControl,
|
|
4
|
+
HtmlTagControl,
|
|
3
5
|
ImageControl,
|
|
6
|
+
InlineEditingControl,
|
|
4
7
|
KeyValueControl,
|
|
5
8
|
LinkControl,
|
|
6
9
|
NumberControl,
|
|
10
|
+
QueryControl,
|
|
7
11
|
RepeatableControl,
|
|
8
|
-
|
|
12
|
+
SelectControlWrapper,
|
|
9
13
|
SizeControl,
|
|
10
14
|
SvgMediaControl,
|
|
11
15
|
SwitchControl,
|
|
12
16
|
TextAreaControl,
|
|
13
17
|
TextControl,
|
|
18
|
+
ToggleControl,
|
|
14
19
|
UrlControl,
|
|
15
20
|
} from '@elementor/editor-controls';
|
|
16
21
|
import { type ControlLayout } from '@elementor/editor-elements';
|
|
17
22
|
import {
|
|
18
23
|
booleanPropTypeUtil,
|
|
24
|
+
DateTimePropTypeUtil,
|
|
25
|
+
htmlPropTypeUtil,
|
|
19
26
|
imagePropTypeUtil,
|
|
20
27
|
imageSrcPropTypeUtil,
|
|
21
28
|
keyValuePropTypeUtil,
|
|
22
29
|
linkPropTypeUtil,
|
|
23
30
|
numberPropTypeUtil,
|
|
24
31
|
type PropTypeUtil,
|
|
32
|
+
queryPropTypeUtil,
|
|
25
33
|
sizePropTypeUtil,
|
|
26
34
|
stringPropTypeUtil,
|
|
27
35
|
} from '@elementor/editor-props';
|
|
28
36
|
|
|
29
37
|
import { ControlTypeAlreadyRegisteredError, ControlTypeNotRegisteredError } from '../errors';
|
|
30
38
|
|
|
31
|
-
type ControlRegistry = Record<
|
|
39
|
+
export type ControlRegistry = Record<
|
|
32
40
|
string,
|
|
33
41
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
34
42
|
{ component: ControlComponent; layout: ControlLayout; propTypeUtil?: PropTypeUtil< string, any > }
|
|
@@ -40,13 +48,18 @@ const controlTypes = {
|
|
|
40
48
|
text: { component: TextControl, layout: 'full', propTypeUtil: stringPropTypeUtil },
|
|
41
49
|
textarea: { component: TextAreaControl, layout: 'full', propTypeUtil: stringPropTypeUtil },
|
|
42
50
|
size: { component: SizeControl, layout: 'two-columns', propTypeUtil: sizePropTypeUtil },
|
|
43
|
-
select: { component:
|
|
51
|
+
select: { component: SelectControlWrapper, layout: 'two-columns', propTypeUtil: stringPropTypeUtil },
|
|
44
52
|
link: { component: LinkControl, layout: 'custom', propTypeUtil: linkPropTypeUtil },
|
|
53
|
+
query: { component: QueryControl, layout: 'full', propTypeUtil: queryPropTypeUtil },
|
|
45
54
|
url: { component: UrlControl, layout: 'full', propTypeUtil: stringPropTypeUtil },
|
|
46
55
|
switch: { component: SwitchControl, layout: 'two-columns', propTypeUtil: booleanPropTypeUtil },
|
|
47
56
|
number: { component: NumberControl, layout: 'two-columns', propTypeUtil: numberPropTypeUtil },
|
|
48
57
|
repeatable: { component: RepeatableControl, layout: 'full', propTypeUtil: undefined },
|
|
49
58
|
'key-value': { component: KeyValueControl, layout: 'full', propTypeUtil: keyValuePropTypeUtil },
|
|
59
|
+
'html-tag': { component: HtmlTagControl, layout: 'two-columns', propTypeUtil: stringPropTypeUtil },
|
|
60
|
+
toggle: { component: ToggleControl, layout: 'full', propTypeUtil: stringPropTypeUtil },
|
|
61
|
+
'date-time': { component: DateTimeControl, layout: 'full', propTypeUtil: DateTimePropTypeUtil },
|
|
62
|
+
'inline-editing': { component: InlineEditingControl, layout: 'full', propTypeUtil: htmlPropTypeUtil },
|
|
50
63
|
} as const satisfies ControlRegistry;
|
|
51
64
|
|
|
52
65
|
export type ControlType = keyof typeof controlTypes;
|
|
@@ -56,7 +69,7 @@ export type ControlTypes = {
|
|
|
56
69
|
};
|
|
57
70
|
|
|
58
71
|
class ControlsRegistry {
|
|
59
|
-
constructor( private readonly controlsRegistry: ControlRegistry
|
|
72
|
+
constructor( private readonly controlsRegistry: ControlRegistry ) {
|
|
60
73
|
this.controlsRegistry = controlsRegistry;
|
|
61
74
|
}
|
|
62
75
|
|
|
@@ -98,4 +111,4 @@ class ControlsRegistry {
|
|
|
98
111
|
}
|
|
99
112
|
}
|
|
100
113
|
|
|
101
|
-
export const controlsRegistry = new ControlsRegistry();
|
|
114
|
+
export const controlsRegistry = new ControlsRegistry( controlTypes );
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { getContainer } from '@elementor/editor-elements';
|
|
2
|
+
|
|
3
|
+
export const getElementByType = ( elementId: string, type: string ) => {
|
|
4
|
+
const currentElement = getContainer( elementId );
|
|
5
|
+
|
|
6
|
+
if ( ! currentElement ) {
|
|
7
|
+
throw new Error( `Current element not found, elementId: ${ elementId }` );
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if ( currentElement.model.get( 'elType' ) === type ) {
|
|
11
|
+
return currentElement;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const element = currentElement.children?.findRecursive?.( ( child ) => child.model.get( 'elType' ) === type );
|
|
15
|
+
|
|
16
|
+
if ( ! element ) {
|
|
17
|
+
throw new Error( `Child element ${ type } not found` );
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return element;
|
|
21
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type ControlComponent } from '@elementor/editor-controls';
|
|
2
|
+
|
|
3
|
+
import { type ControlRegistry, controlsRegistry } from '../controls-registry';
|
|
4
|
+
import { TabsControl } from './tabs-control/tabs-control';
|
|
5
|
+
|
|
6
|
+
const controlTypes = {
|
|
7
|
+
tabs: { component: TabsControl as ControlComponent, layout: 'full' },
|
|
8
|
+
} as const satisfies ControlRegistry;
|
|
9
|
+
|
|
10
|
+
export const registerElementControls = () => {
|
|
11
|
+
Object.entries< ( typeof controlTypes )[ keyof typeof controlTypes ] >( controlTypes ).forEach(
|
|
12
|
+
( [ type, { component, layout } ] ) => {
|
|
13
|
+
controlsRegistry.register( type, component, layout );
|
|
14
|
+
}
|
|
15
|
+
);
|
|
16
|
+
};
|