@elementor/editor-editing-panel 1.45.0 → 1.47.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 +90 -0
- package/dist/index.d.mts +22 -4
- package/dist/index.d.ts +22 -4
- package/dist/index.js +1187 -1051
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1027 -893
- package/dist/index.mjs.map +1 -1
- package/package.json +18 -17
- package/src/components/css-classes/css-class-menu.tsx +6 -8
- package/src/components/css-classes/css-class-selector.tsx +17 -11
- package/src/components/popover-scrollable-content.tsx +12 -0
- package/src/components/section-content.tsx +6 -16
- package/src/components/section.tsx +8 -4
- package/src/components/settings-tab.tsx +30 -4
- package/src/components/style-indicator.tsx +19 -15
- package/src/components/style-sections/background-section/background-section.tsx +4 -1
- package/src/components/style-sections/border-section/border-color-field.tsx +10 -16
- package/src/components/style-sections/border-section/border-field.tsx +4 -6
- package/src/components/style-sections/border-section/border-radius-field.tsx +4 -2
- package/src/components/style-sections/border-section/border-style-field.tsx +11 -16
- package/src/components/style-sections/border-section/border-width-field.tsx +4 -2
- package/src/components/style-sections/effects-section/effects-section.tsx +22 -2
- package/src/components/style-sections/layout-section/align-content-field.tsx +11 -12
- package/src/components/style-sections/layout-section/align-items-field.tsx +8 -11
- package/src/components/style-sections/layout-section/align-self-child-field.tsx +11 -16
- package/src/components/style-sections/layout-section/display-field.tsx +6 -6
- package/src/components/style-sections/layout-section/flex-direction-field.tsx +11 -14
- package/src/components/style-sections/layout-section/flex-order-field.tsx +32 -37
- package/src/components/style-sections/layout-section/flex-size-field.tsx +35 -58
- package/src/components/style-sections/layout-section/gap-control-field.tsx +5 -6
- package/src/components/style-sections/layout-section/justify-content-field.tsx +11 -12
- package/src/components/style-sections/layout-section/layout-section.tsx +2 -2
- package/src/components/style-sections/layout-section/opacity-control-field.tsx +21 -0
- package/src/components/style-sections/layout-section/utils/rotated-icon.tsx +1 -1
- package/src/components/style-sections/layout-section/wrap-field.tsx +10 -14
- package/src/components/style-sections/position-section/dimensions-field.tsx +4 -4
- package/src/components/style-sections/position-section/offset-field.tsx +12 -14
- package/src/components/style-sections/position-section/position-field.tsx +7 -11
- package/src/components/style-sections/position-section/position-section.tsx +6 -6
- package/src/components/style-sections/position-section/z-index-field.tsx +7 -11
- package/src/components/style-sections/size-section/object-fit-field.tsx +7 -11
- package/src/components/style-sections/size-section/object-position-field.tsx +4 -23
- package/src/components/style-sections/size-section/overflow-field.tsx +7 -11
- package/src/components/style-sections/size-section/size-section.tsx +10 -8
- package/src/components/style-sections/spacing-section/spacing-section.tsx +7 -4
- package/src/components/style-sections/typography-section/column-count-field.tsx +7 -11
- package/src/components/style-sections/typography-section/column-gap-field.tsx +9 -13
- package/src/components/style-sections/typography-section/font-family-field.tsx +9 -11
- package/src/components/style-sections/typography-section/font-size-field.tsx +9 -13
- package/src/components/style-sections/typography-section/font-style-field.tsx +13 -13
- package/src/components/style-sections/typography-section/font-weight-field.tsx +7 -11
- package/src/components/style-sections/typography-section/letter-spacing-field.tsx +9 -13
- package/src/components/style-sections/typography-section/line-height-field.tsx +9 -13
- package/src/components/style-sections/typography-section/text-alignment-field.tsx +11 -14
- package/src/components/style-sections/typography-section/text-color-field.tsx +7 -11
- package/src/components/style-sections/typography-section/text-decoration-field.tsx +7 -11
- package/src/components/style-sections/typography-section/text-direction-field.tsx +7 -11
- package/src/components/style-sections/typography-section/text-stroke-field.tsx +8 -8
- package/src/components/style-sections/typography-section/transform-field.tsx +7 -11
- package/src/components/style-sections/typography-section/typography-section.tsx +4 -2
- package/src/components/style-sections/typography-section/word-spacing-field.tsx +9 -13
- package/src/components/styles-field-layout.tsx +50 -0
- package/src/contexts/section-context.tsx +14 -0
- package/src/controls-registry/control-type-container.tsx +6 -2
- package/src/controls-registry/controls-registry.tsx +30 -10
- package/src/controls-registry/settings-field.tsx +65 -6
- package/src/controls-registry/styles-field.tsx +11 -5
- package/src/dynamics/components/dynamic-selection-control.tsx +20 -22
- package/src/dynamics/components/dynamic-selection.tsx +64 -79
- package/src/dynamics/hooks/use-prop-dynamic-action.tsx +1 -1
- package/src/hooks/use-default-panel-settings.ts +4 -0
- package/src/hooks/use-styles-field.ts +9 -3
- package/src/hooks/use-styles-fields.ts +4 -4
- package/src/index.ts +5 -0
- package/src/popover-action.tsx +11 -6
- package/src/provider-colors-registry.ts +20 -0
- package/src/styles-inheritance/components/infotip/label-chip.tsx +4 -5
- package/src/styles-inheritance/components/styles-inheritance-indicator.tsx +36 -41
- package/src/styles-inheritance/components/styles-inheritance-infotip.tsx +10 -24
- package/src/styles-inheritance/components/styles-inheritance-section-indicators.tsx +29 -44
- package/src/styles-inheritance/hooks/use-normalized-inheritance-chain-items.tsx +1 -17
- package/src/styles-inheritance/types.ts +0 -2
- package/src/styles-inheritance/utils.ts +17 -1
- package/src/sync/experiments-flags.ts +1 -0
- package/src/utils/get-styles-provider-color.ts +28 -0
- package/src/components/popover-content.tsx +0 -15
|
@@ -1,22 +1,18 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { ColorControl } from '@elementor/editor-controls';
|
|
3
|
-
import { Grid } from '@elementor/ui';
|
|
4
3
|
import { __ } from '@wordpress/i18n';
|
|
5
4
|
|
|
6
5
|
import { StylesField } from '../../../controls-registry/styles-field';
|
|
7
|
-
import {
|
|
6
|
+
import { StylesFieldLayout } from '../../styles-field-layout';
|
|
7
|
+
|
|
8
|
+
const TEXT_COLOR_LABEL = __( 'Text color', 'elementor' );
|
|
8
9
|
|
|
9
10
|
export const TextColorField = () => {
|
|
10
11
|
return (
|
|
11
|
-
<StylesField bind="color">
|
|
12
|
-
<
|
|
13
|
-
<
|
|
14
|
-
|
|
15
|
-
</Grid>
|
|
16
|
-
<Grid item xs={ 6 }>
|
|
17
|
-
<ColorControl />
|
|
18
|
-
</Grid>
|
|
19
|
-
</Grid>
|
|
12
|
+
<StylesField bind="color" propDisplayName={ TEXT_COLOR_LABEL }>
|
|
13
|
+
<StylesFieldLayout label={ TEXT_COLOR_LABEL }>
|
|
14
|
+
<ColorControl />
|
|
15
|
+
</StylesFieldLayout>
|
|
20
16
|
</StylesField>
|
|
21
17
|
);
|
|
22
18
|
};
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { ToggleControl, type ToggleControlProps } from '@elementor/editor-controls';
|
|
3
3
|
import { MinusIcon, OverlineIcon, StrikethroughIcon, UnderlineIcon } from '@elementor/icons';
|
|
4
|
-
import { Grid } from '@elementor/ui';
|
|
5
4
|
import { __ } from '@wordpress/i18n';
|
|
6
5
|
|
|
7
6
|
import { StylesField } from '../../../controls-registry/styles-field';
|
|
8
|
-
import {
|
|
7
|
+
import { StylesFieldLayout } from '../../styles-field-layout';
|
|
9
8
|
|
|
10
9
|
type Decoration = 'none' | 'underline' | 'line-through' | 'overline';
|
|
11
10
|
|
|
11
|
+
const TEXT_DECORATION_LABEL = __( 'Line decoration', 'elementor' );
|
|
12
|
+
|
|
12
13
|
const options: ToggleControlProps< Decoration >[ 'options' ] = [
|
|
13
14
|
{
|
|
14
15
|
value: 'none',
|
|
@@ -37,14 +38,9 @@ const options: ToggleControlProps< Decoration >[ 'options' ] = [
|
|
|
37
38
|
},
|
|
38
39
|
];
|
|
39
40
|
export const TextDecorationField = () => (
|
|
40
|
-
<StylesField bind=
|
|
41
|
-
<
|
|
42
|
-
<
|
|
43
|
-
|
|
44
|
-
</Grid>
|
|
45
|
-
<Grid item xs={ 6 } display="flex" justifyContent="end">
|
|
46
|
-
<ToggleControl options={ options } exclusive={ false } />
|
|
47
|
-
</Grid>
|
|
48
|
-
</Grid>
|
|
41
|
+
<StylesField bind="text-decoration" propDisplayName={ TEXT_DECORATION_LABEL }>
|
|
42
|
+
<StylesFieldLayout label={ TEXT_DECORATION_LABEL }>
|
|
43
|
+
<ToggleControl options={ options } exclusive={ false } />
|
|
44
|
+
</StylesFieldLayout>
|
|
49
45
|
</StylesField>
|
|
50
46
|
);
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { type ToggleButtonGroupItem, ToggleControl } from '@elementor/editor-controls';
|
|
3
3
|
import { TextDirectionLtrIcon, TextDirectionRtlIcon } from '@elementor/icons';
|
|
4
|
-
import { Grid } from '@elementor/ui';
|
|
5
4
|
import { __ } from '@wordpress/i18n';
|
|
6
5
|
|
|
7
6
|
import { StylesField } from '../../../controls-registry/styles-field';
|
|
8
|
-
import {
|
|
7
|
+
import { StylesFieldLayout } from '../../styles-field-layout';
|
|
9
8
|
|
|
10
9
|
type Direction = 'ltr' | 'rtl';
|
|
11
10
|
|
|
11
|
+
const TEXT_DIRECTION_LABEL = __( 'Direction', 'elementor' );
|
|
12
|
+
|
|
12
13
|
const options: ToggleButtonGroupItem< Direction >[] = [
|
|
13
14
|
{
|
|
14
15
|
value: 'ltr',
|
|
@@ -26,15 +27,10 @@ const options: ToggleButtonGroupItem< Direction >[] = [
|
|
|
26
27
|
|
|
27
28
|
export const TextDirectionField = () => {
|
|
28
29
|
return (
|
|
29
|
-
<StylesField bind={
|
|
30
|
-
<
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
</Grid>
|
|
34
|
-
<Grid item xs={ 6 } display="flex" justifyContent="end">
|
|
35
|
-
<ToggleControl options={ options } />
|
|
36
|
-
</Grid>
|
|
37
|
-
</Grid>
|
|
30
|
+
<StylesField bind="direction" propDisplayName={ TEXT_DIRECTION_LABEL }>
|
|
31
|
+
<StylesFieldLayout label={ TEXT_DIRECTION_LABEL }>
|
|
32
|
+
<ToggleControl options={ options } />
|
|
33
|
+
</StylesFieldLayout>
|
|
38
34
|
</StylesField>
|
|
39
35
|
);
|
|
40
36
|
};
|
|
@@ -2,7 +2,6 @@ import * as React from 'react';
|
|
|
2
2
|
import { StrokeControl } from '@elementor/editor-controls';
|
|
3
3
|
import { __ } from '@wordpress/i18n';
|
|
4
4
|
|
|
5
|
-
import { useStyle } from '../../../contexts/style-context';
|
|
6
5
|
import { StylesField } from '../../../controls-registry/styles-field';
|
|
7
6
|
import { useStylesField } from '../../../hooks/use-styles-field';
|
|
8
7
|
import { AddOrRemoveContent } from '../../add-or-remove-content';
|
|
@@ -25,28 +24,29 @@ const initTextStroke = {
|
|
|
25
24
|
},
|
|
26
25
|
};
|
|
27
26
|
|
|
27
|
+
const TEXT_STROKE_LABEL = __( 'Text stroke', 'elementor' );
|
|
28
|
+
|
|
28
29
|
export const TextStrokeField = () => {
|
|
29
|
-
const { canEdit } =
|
|
30
|
-
const [ textStroke, setTextStroke ] = useStylesField( 'stroke' );
|
|
30
|
+
const { value, setValue, canEdit } = useStylesField( 'stroke' );
|
|
31
31
|
|
|
32
32
|
const addTextStroke = () => {
|
|
33
|
-
|
|
33
|
+
setValue( initTextStroke );
|
|
34
34
|
};
|
|
35
35
|
|
|
36
36
|
const removeTextStroke = () => {
|
|
37
|
-
|
|
37
|
+
setValue( null );
|
|
38
38
|
};
|
|
39
39
|
|
|
40
|
-
const hasTextStroke = Boolean(
|
|
40
|
+
const hasTextStroke = Boolean( value );
|
|
41
41
|
|
|
42
42
|
return (
|
|
43
|
-
<StylesField bind={ 'stroke' }>
|
|
43
|
+
<StylesField bind={ 'stroke' } propDisplayName={ TEXT_STROKE_LABEL }>
|
|
44
44
|
<AddOrRemoveContent
|
|
45
45
|
isAdded={ hasTextStroke }
|
|
46
46
|
onAdd={ addTextStroke }
|
|
47
47
|
onRemove={ removeTextStroke }
|
|
48
48
|
disabled={ ! canEdit }
|
|
49
|
-
renderLabel={ () => <ControlLabel>{
|
|
49
|
+
renderLabel={ () => <ControlLabel>{ TEXT_STROKE_LABEL }</ControlLabel> }
|
|
50
50
|
>
|
|
51
51
|
<StrokeControl />
|
|
52
52
|
</AddOrRemoveContent>
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { type ToggleButtonGroupItem, ToggleControl } from '@elementor/editor-controls';
|
|
3
3
|
import { LetterCaseIcon, LetterCaseLowerIcon, LetterCaseUpperIcon, MinusIcon } from '@elementor/icons';
|
|
4
|
-
import { Grid } from '@elementor/ui';
|
|
5
4
|
import { __ } from '@wordpress/i18n';
|
|
6
5
|
|
|
7
6
|
import { StylesField } from '../../../controls-registry/styles-field';
|
|
8
|
-
import {
|
|
7
|
+
import { StylesFieldLayout } from '../../styles-field-layout';
|
|
9
8
|
|
|
10
9
|
type Transforms = 'none' | 'capitalize' | 'uppercase' | 'lowercase';
|
|
11
10
|
|
|
11
|
+
const TEXT_TRANSFORM_LABEL = __( 'Text transform', 'elementor' );
|
|
12
|
+
|
|
12
13
|
const options: ToggleButtonGroupItem< Transforms >[] = [
|
|
13
14
|
{
|
|
14
15
|
value: 'none',
|
|
@@ -37,14 +38,9 @@ const options: ToggleButtonGroupItem< Transforms >[] = [
|
|
|
37
38
|
];
|
|
38
39
|
|
|
39
40
|
export const TransformField = () => (
|
|
40
|
-
<StylesField bind=
|
|
41
|
-
<
|
|
42
|
-
<
|
|
43
|
-
|
|
44
|
-
</Grid>
|
|
45
|
-
<Grid item xs={ 6 } display="flex" justifyContent="end">
|
|
46
|
-
<ToggleControl options={ options } />
|
|
47
|
-
</Grid>
|
|
48
|
-
</Grid>
|
|
41
|
+
<StylesField bind="text-transform" propDisplayName={ TEXT_TRANSFORM_LABEL }>
|
|
42
|
+
<StylesFieldLayout label={ TEXT_TRANSFORM_LABEL }>
|
|
43
|
+
<ToggleControl options={ options } />
|
|
44
|
+
</StylesFieldLayout>
|
|
49
45
|
</StylesField>
|
|
50
46
|
);
|
|
@@ -23,9 +23,11 @@ import { TransformField } from './transform-field';
|
|
|
23
23
|
import { WordSpacingField } from './word-spacing-field';
|
|
24
24
|
|
|
25
25
|
export const TypographySection = () => {
|
|
26
|
-
const
|
|
27
|
-
const isVersion330Active = isExperimentActive( 'e_v_3_30' );
|
|
26
|
+
const { value: columnCount } = useStylesField< NumberPropValue >( 'column-count' );
|
|
28
27
|
const hasMultiColumns = !! ( columnCount?.value && columnCount?.value > 1 );
|
|
28
|
+
|
|
29
|
+
const isVersion330Active = isExperimentActive( 'e_v_3_30' );
|
|
30
|
+
|
|
29
31
|
return (
|
|
30
32
|
<SectionContent>
|
|
31
33
|
<FontFamilyField />
|
|
@@ -1,25 +1,21 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useRef } from 'react';
|
|
3
3
|
import { SizeControl } from '@elementor/editor-controls';
|
|
4
|
-
import { Grid } from '@elementor/ui';
|
|
5
4
|
import { __ } from '@wordpress/i18n';
|
|
6
5
|
|
|
7
6
|
import { StylesField } from '../../../controls-registry/styles-field';
|
|
8
|
-
import {
|
|
7
|
+
import { StylesFieldLayout } from '../../styles-field-layout';
|
|
8
|
+
|
|
9
|
+
const WORD_SPACING_LABEL = __( 'Word spacing', 'elementor' );
|
|
9
10
|
|
|
10
11
|
export const WordSpacingField = () => {
|
|
11
|
-
const rowRef
|
|
12
|
+
const rowRef = useRef< HTMLDivElement >( null );
|
|
12
13
|
|
|
13
14
|
return (
|
|
14
|
-
<StylesField bind="word-spacing">
|
|
15
|
-
<
|
|
16
|
-
<
|
|
17
|
-
|
|
18
|
-
</Grid>
|
|
19
|
-
<Grid item xs={ 6 }>
|
|
20
|
-
<SizeControl anchorRef={ rowRef } />
|
|
21
|
-
</Grid>
|
|
22
|
-
</Grid>
|
|
15
|
+
<StylesField bind="word-spacing" propDisplayName={ WORD_SPACING_LABEL }>
|
|
16
|
+
<StylesFieldLayout label={ WORD_SPACING_LABEL } ref={ rowRef }>
|
|
17
|
+
<SizeControl anchorRef={ rowRef } />
|
|
18
|
+
</StylesFieldLayout>
|
|
23
19
|
</StylesField>
|
|
24
20
|
);
|
|
25
21
|
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Grid, Stack, type Theme } from '@elementor/ui';
|
|
3
|
+
|
|
4
|
+
import { ControlLabel } from './control-label';
|
|
5
|
+
|
|
6
|
+
type StylesFieldLayoutProps = {
|
|
7
|
+
label: string;
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
direction?: 'row' | 'column';
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const StylesFieldLayout = React.forwardRef< HTMLDivElement, StylesFieldLayoutProps >( ( props, ref ) => {
|
|
13
|
+
const { direction = 'row', children, label } = props;
|
|
14
|
+
|
|
15
|
+
const LayoutComponent = direction === 'row' ? Row : Column;
|
|
16
|
+
|
|
17
|
+
return <LayoutComponent label={ label } ref={ ref } children={ children } />;
|
|
18
|
+
} );
|
|
19
|
+
|
|
20
|
+
const Row = React.forwardRef< HTMLDivElement, { label: string; children: React.ReactNode } >(
|
|
21
|
+
( { label, children }, ref ) => {
|
|
22
|
+
return (
|
|
23
|
+
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap" ref={ ref }>
|
|
24
|
+
<Grid item xs={ 6 }>
|
|
25
|
+
<ControlLabel>{ label }</ControlLabel>
|
|
26
|
+
</Grid>
|
|
27
|
+
<Grid
|
|
28
|
+
item
|
|
29
|
+
xs={ 6 }
|
|
30
|
+
sx={ ( theme: Theme ) => ( {
|
|
31
|
+
width: `calc(50% - ${ theme.spacing( 2 ) })`,
|
|
32
|
+
} ) }
|
|
33
|
+
>
|
|
34
|
+
{ children }
|
|
35
|
+
</Grid>
|
|
36
|
+
</Grid>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const Column = React.forwardRef< HTMLDivElement, { label: string; children: React.ReactNode } >(
|
|
42
|
+
( { label, children }, ref ) => {
|
|
43
|
+
return (
|
|
44
|
+
<Stack gap={ 0.75 } ref={ ref }>
|
|
45
|
+
<ControlLabel>{ label }</ControlLabel>
|
|
46
|
+
{ children }
|
|
47
|
+
</Stack>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
import type { RefObject } from 'react';
|
|
3
|
+
|
|
4
|
+
const FALLBACK_SECTION_WIDTH = 320;
|
|
5
|
+
|
|
6
|
+
export const SectionRefContext = createContext< RefObject< HTMLElement > | null >( null );
|
|
7
|
+
|
|
8
|
+
const useSectionRef = () => useContext( SectionRefContext );
|
|
9
|
+
|
|
10
|
+
export const useSectionWidth = (): number => {
|
|
11
|
+
const sectionRef = useSectionRef();
|
|
12
|
+
|
|
13
|
+
return sectionRef?.current?.offsetWidth ?? FALLBACK_SECTION_WIDTH;
|
|
14
|
+
};
|
|
@@ -3,6 +3,10 @@ import { type ControlLayout } from '@elementor/editor-elements';
|
|
|
3
3
|
import { Box, type BoxProps, styled } from '@elementor/ui';
|
|
4
4
|
|
|
5
5
|
export const ControlTypeContainer = ( { children, layout }: React.PropsWithChildren< { layout?: ControlLayout } > ) => {
|
|
6
|
+
if ( layout === 'custom' ) {
|
|
7
|
+
return children;
|
|
8
|
+
}
|
|
9
|
+
|
|
6
10
|
return <StyledContainer layout={ layout }>{ children }</StyledContainer>;
|
|
7
11
|
};
|
|
8
12
|
|
|
@@ -14,10 +18,10 @@ const StyledContainer = styled( Box, {
|
|
|
14
18
|
...getGridLayout( layout ),
|
|
15
19
|
} ) );
|
|
16
20
|
|
|
17
|
-
const getGridLayout = ( layout: ControlLayout ) => ( {
|
|
21
|
+
const getGridLayout = ( layout: Omit< ControlLayout, 'custom' > ) => ( {
|
|
18
22
|
justifyContent: 'space-between',
|
|
19
23
|
gridTemplateColumns: {
|
|
20
24
|
full: 'minmax(0, 1fr)',
|
|
21
25
|
'two-columns': 'repeat(2, minmax(0, 1fr))',
|
|
22
|
-
}[ layout ],
|
|
26
|
+
}[ layout as string ],
|
|
23
27
|
} );
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type ControlComponent,
|
|
3
3
|
ImageControl,
|
|
4
|
+
KeyValueControl,
|
|
4
5
|
LinkControl,
|
|
6
|
+
RepeatableControl,
|
|
5
7
|
SelectControl,
|
|
6
8
|
SizeControl,
|
|
7
9
|
SvgMediaControl,
|
|
@@ -11,19 +13,35 @@ import {
|
|
|
11
13
|
UrlControl,
|
|
12
14
|
} from '@elementor/editor-controls';
|
|
13
15
|
import { type ControlLayout } from '@elementor/editor-elements';
|
|
16
|
+
import {
|
|
17
|
+
booleanPropTypeUtil,
|
|
18
|
+
imagePropTypeUtil,
|
|
19
|
+
imageSrcPropTypeUtil,
|
|
20
|
+
keyValuePropTypeUtil,
|
|
21
|
+
linkPropTypeUtil,
|
|
22
|
+
type PropTypeUtil,
|
|
23
|
+
sizePropTypeUtil,
|
|
24
|
+
stringPropTypeUtil,
|
|
25
|
+
} from '@elementor/editor-props';
|
|
14
26
|
|
|
15
|
-
type ControlRegistry = Record<
|
|
27
|
+
type ControlRegistry = Record<
|
|
28
|
+
string,
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
|
+
{ component: ControlComponent; layout: ControlLayout; propTypeUtil?: PropTypeUtil< string, any > }
|
|
31
|
+
>;
|
|
16
32
|
|
|
17
33
|
const controlTypes = {
|
|
18
|
-
image: { component: ImageControl, layout: 'full' },
|
|
19
|
-
'svg-media': { component: SvgMediaControl, layout: 'full' },
|
|
20
|
-
text: { component: TextControl, layout: 'full' },
|
|
21
|
-
textarea: { component: TextAreaControl, layout: 'full' },
|
|
22
|
-
size: { component: SizeControl, layout: 'two-columns' },
|
|
23
|
-
select: { component: SelectControl, layout: 'two-columns' },
|
|
24
|
-
link: { component: LinkControl, layout: '
|
|
25
|
-
url: { component: UrlControl, layout: 'full' },
|
|
26
|
-
switch: { component: SwitchControl, layout: 'two-columns' },
|
|
34
|
+
image: { component: ImageControl, layout: 'full', propTypeUtil: imagePropTypeUtil },
|
|
35
|
+
'svg-media': { component: SvgMediaControl, layout: 'full', propTypeUtil: imageSrcPropTypeUtil },
|
|
36
|
+
text: { component: TextControl, layout: 'full', propTypeUtil: stringPropTypeUtil },
|
|
37
|
+
textarea: { component: TextAreaControl, layout: 'full', propTypeUtil: stringPropTypeUtil },
|
|
38
|
+
size: { component: SizeControl, layout: 'two-columns', propTypeUtil: sizePropTypeUtil },
|
|
39
|
+
select: { component: SelectControl, layout: 'two-columns', propTypeUtil: stringPropTypeUtil },
|
|
40
|
+
link: { component: LinkControl, layout: 'custom', propTypeUtil: linkPropTypeUtil },
|
|
41
|
+
url: { component: UrlControl, layout: 'full', propTypeUtil: stringPropTypeUtil },
|
|
42
|
+
switch: { component: SwitchControl, layout: 'two-columns', propTypeUtil: booleanPropTypeUtil },
|
|
43
|
+
repeatable: { component: RepeatableControl, layout: 'full', propTypeUtil: undefined },
|
|
44
|
+
'key-value': { component: KeyValueControl, layout: 'full', propTypeUtil: keyValuePropTypeUtil },
|
|
27
45
|
} as const satisfies ControlRegistry;
|
|
28
46
|
|
|
29
47
|
export type ControlType = keyof typeof controlTypes;
|
|
@@ -35,3 +53,5 @@ export type ControlTypes = {
|
|
|
35
53
|
export const getControl = ( type: ControlType ) => controlTypes[ type ]?.component;
|
|
36
54
|
|
|
37
55
|
export const getDefaultLayout = ( type: ControlType ) => controlTypes[ type ].layout;
|
|
56
|
+
|
|
57
|
+
export const getPropTypeUtil = ( type: ControlType ) => controlTypes[ type ]?.propTypeUtil;
|
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { useMemo } from 'react';
|
|
2
3
|
import { PropKeyProvider, PropProvider } from '@elementor/editor-controls';
|
|
3
|
-
import {
|
|
4
|
+
import { setDocumentModifiedStatus } from '@elementor/editor-documents';
|
|
5
|
+
import {
|
|
6
|
+
type ElementID,
|
|
7
|
+
getElementLabel,
|
|
8
|
+
getElementSetting,
|
|
9
|
+
updateElementSettings,
|
|
10
|
+
useElementSetting,
|
|
11
|
+
} from '@elementor/editor-elements';
|
|
4
12
|
import { type PropKey, type PropValue } from '@elementor/editor-props';
|
|
13
|
+
import { isExperimentActive, undoable } from '@elementor/editor-v1-adapters';
|
|
14
|
+
import { __ } from '@wordpress/i18n';
|
|
5
15
|
|
|
6
16
|
import { useElement } from '../contexts/element-context';
|
|
17
|
+
import { EXPERIMENTAL_FEATURES } from '../sync/experiments-flags';
|
|
7
18
|
import { createTopLevelOjectType } from './create-top-level-object-type';
|
|
8
19
|
|
|
9
20
|
type Props = {
|
|
10
21
|
bind: PropKey;
|
|
22
|
+
propDisplayName: string;
|
|
11
23
|
children: React.ReactNode;
|
|
12
24
|
};
|
|
13
25
|
|
|
14
|
-
export const SettingsField = ( { bind, children }: Props ) => {
|
|
26
|
+
export const SettingsField = ( { bind, children, propDisplayName }: Props ) => {
|
|
15
27
|
const { element, elementType } = useElement();
|
|
16
28
|
|
|
17
29
|
const settingsValue = useElementSetting< PropValue >( element.id, bind );
|
|
@@ -20,11 +32,20 @@ export const SettingsField = ( { bind, children }: Props ) => {
|
|
|
20
32
|
|
|
21
33
|
const propType = createTopLevelOjectType( { schema: elementType.propsSchema } );
|
|
22
34
|
|
|
35
|
+
const undoableUpdateElementProp = useUndoableUpdateElementProp( {
|
|
36
|
+
propKey: bind,
|
|
37
|
+
elementId: element.id,
|
|
38
|
+
propDisplayName,
|
|
39
|
+
} );
|
|
40
|
+
|
|
23
41
|
const setValue = ( newValue: Record< string, PropValue > ) => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
42
|
+
const isVersion331Active = isExperimentActive( EXPERIMENTAL_FEATURES.V_3_31 );
|
|
43
|
+
|
|
44
|
+
if ( isVersion331Active ) {
|
|
45
|
+
undoableUpdateElementProp( { newValue } );
|
|
46
|
+
} else {
|
|
47
|
+
updateElementSettings( { id: element.id, props: newValue } );
|
|
48
|
+
}
|
|
28
49
|
};
|
|
29
50
|
|
|
30
51
|
return (
|
|
@@ -33,3 +54,41 @@ export const SettingsField = ( { bind, children }: Props ) => {
|
|
|
33
54
|
</PropProvider>
|
|
34
55
|
);
|
|
35
56
|
};
|
|
57
|
+
|
|
58
|
+
type UndoableUpdateElementSettingsArgs = {
|
|
59
|
+
newValue: Record< string, PropValue >;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
function useUndoableUpdateElementProp( {
|
|
63
|
+
propKey,
|
|
64
|
+
elementId,
|
|
65
|
+
propDisplayName,
|
|
66
|
+
}: {
|
|
67
|
+
propKey: PropKey;
|
|
68
|
+
elementId: ElementID;
|
|
69
|
+
propDisplayName: string;
|
|
70
|
+
} ) {
|
|
71
|
+
return useMemo( () => {
|
|
72
|
+
return undoable(
|
|
73
|
+
{
|
|
74
|
+
do: ( { newValue }: UndoableUpdateElementSettingsArgs ) => {
|
|
75
|
+
const prevPropValue = getElementSetting( elementId, propKey ) as PropValue;
|
|
76
|
+
|
|
77
|
+
updateElementSettings( { id: elementId, props: { ...newValue }, withHistory: false } );
|
|
78
|
+
setDocumentModifiedStatus( true );
|
|
79
|
+
|
|
80
|
+
return { [ propKey ]: prevPropValue };
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
undo: ( {}, prevProps ) => {
|
|
84
|
+
updateElementSettings( { id: elementId, props: prevProps, withHistory: false } );
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
title: getElementLabel( elementId ),
|
|
89
|
+
// translators: %s is the name of the property that was edited.
|
|
90
|
+
subtitle: __( '%s edited', 'elementor' ).replace( '%s', propDisplayName ),
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
}, [ propKey, elementId, propDisplayName ] );
|
|
94
|
+
}
|
|
@@ -2,8 +2,9 @@ import * as React from 'react';
|
|
|
2
2
|
import { ControlAdornmentsProvider, PropKeyProvider, PropProvider } from '@elementor/editor-controls';
|
|
3
3
|
import { type PropKey, type PropValue } from '@elementor/editor-props';
|
|
4
4
|
import { getStylesSchema } from '@elementor/editor-styles';
|
|
5
|
+
import { isExperimentActive } from '@elementor/editor-v1-adapters';
|
|
5
6
|
|
|
6
|
-
import {
|
|
7
|
+
import { useStylesInheritanceChain } from '../contexts/styles-inheritance-context';
|
|
7
8
|
import { useStylesField } from '../hooks/use-styles-field';
|
|
8
9
|
import { StylesInheritanceIndicator } from '../styles-inheritance/components/styles-inheritance-indicator';
|
|
9
10
|
import { createTopLevelOjectType } from './create-top-level-object-type';
|
|
@@ -12,19 +13,24 @@ export type StylesFieldProps = {
|
|
|
12
13
|
bind: PropKey;
|
|
13
14
|
placeholder?: PropValue;
|
|
14
15
|
children: React.ReactNode;
|
|
16
|
+
propDisplayName: string;
|
|
15
17
|
};
|
|
16
18
|
|
|
17
19
|
export const StylesField = ( { bind, placeholder, children }: StylesFieldProps ) => {
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
+
const { value, setValue, canEdit } = useStylesField( bind );
|
|
21
|
+
|
|
22
|
+
const isVersion331Active = isExperimentActive( 'e_v_3_31' );
|
|
23
|
+
const stylesInheritanceChain = useStylesInheritanceChain( [ bind ] );
|
|
20
24
|
|
|
21
25
|
const stylesSchema = getStylesSchema();
|
|
22
26
|
|
|
23
27
|
const propType = createTopLevelOjectType( { schema: stylesSchema } );
|
|
24
28
|
|
|
25
29
|
const values = { [ bind ]: value };
|
|
26
|
-
const
|
|
27
|
-
|
|
30
|
+
const [ actualValue ] = stylesInheritanceChain;
|
|
31
|
+
const placeholderValues = {
|
|
32
|
+
[ bind ]: isVersion331Active ? actualValue?.value : placeholder,
|
|
33
|
+
};
|
|
28
34
|
const setValues = ( newValue: Record< string, PropValue > ) => {
|
|
29
35
|
setValue( newValue[ bind ] );
|
|
30
36
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { ControlFormLabel, useBoundProp } from '@elementor/editor-controls';
|
|
3
3
|
import type { Control, ControlsSection } from '@elementor/editor-elements';
|
|
4
|
-
import { PopoverHeader } from '@elementor/editor-ui';
|
|
4
|
+
import { PopoverHeader, PopoverScrollableContent } from '@elementor/editor-ui';
|
|
5
5
|
import { DatabaseIcon, SettingsIcon, XIcon } from '@elementor/icons';
|
|
6
6
|
import {
|
|
7
7
|
bindPopover,
|
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
Divider,
|
|
11
11
|
Grid,
|
|
12
12
|
IconButton,
|
|
13
|
-
Paper,
|
|
14
13
|
Popover,
|
|
15
14
|
Stack,
|
|
16
15
|
Tab,
|
|
@@ -22,7 +21,6 @@ import {
|
|
|
22
21
|
} from '@elementor/ui';
|
|
23
22
|
import { __ } from '@wordpress/i18n';
|
|
24
23
|
|
|
25
|
-
import { PopoverContent } from '../../components/popover-content';
|
|
26
24
|
import { Control as BaseControl } from '../../controls-registry/control';
|
|
27
25
|
import { type ControlType, getControl } from '../../controls-registry/controls-registry';
|
|
28
26
|
import { usePersistDynamicValue } from '../../hooks/use-persist-dynamic-value';
|
|
@@ -77,16 +75,15 @@ export const DynamicSelectionControl = () => {
|
|
|
77
75
|
<Popover
|
|
78
76
|
disablePortal
|
|
79
77
|
disableScrollLock
|
|
80
|
-
anchorOrigin={ { vertical: 'bottom', horizontal: '
|
|
78
|
+
anchorOrigin={ { vertical: 'bottom', horizontal: 'right' } }
|
|
79
|
+
transformOrigin={ { vertical: 'top', horizontal: 'right' } }
|
|
80
|
+
PaperProps={ {
|
|
81
|
+
sx: { my: 1 },
|
|
82
|
+
} }
|
|
81
83
|
{ ...bindPopover( selectionPopoverState ) }
|
|
82
84
|
>
|
|
83
85
|
<Stack>
|
|
84
|
-
<
|
|
85
|
-
title={ __( 'Dynamic tags', 'elementor' ) }
|
|
86
|
-
onClose={ selectionPopoverState.close }
|
|
87
|
-
icon={ <DatabaseIcon fontSize={ SIZE } /> }
|
|
88
|
-
/>
|
|
89
|
-
<DynamicSelection onSelect={ selectionPopoverState.close } />
|
|
86
|
+
<DynamicSelection close={ selectionPopoverState.close } />
|
|
90
87
|
</Stack>
|
|
91
88
|
</Popover>
|
|
92
89
|
</Box>
|
|
@@ -111,16 +108,17 @@ export const DynamicSettingsPopover = ( { dynamicTag }: { dynamicTag: DynamicTag
|
|
|
111
108
|
disablePortal
|
|
112
109
|
disableScrollLock
|
|
113
110
|
anchorOrigin={ { vertical: 'bottom', horizontal: 'center' } }
|
|
111
|
+
PaperProps={ {
|
|
112
|
+
sx: { my: 0.5 },
|
|
113
|
+
} }
|
|
114
114
|
{ ...bindPopover( popupState ) }
|
|
115
115
|
>
|
|
116
|
-
<
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
<DynamicSettings controls={ dynamicTag.atomic_controls } />
|
|
123
|
-
</Paper>
|
|
116
|
+
<PopoverHeader
|
|
117
|
+
title={ dynamicTag.label }
|
|
118
|
+
onClose={ popupState.close }
|
|
119
|
+
icon={ <DatabaseIcon fontSize={ SIZE } /> }
|
|
120
|
+
/>
|
|
121
|
+
<DynamicSettings controls={ dynamicTag.atomic_controls } />
|
|
124
122
|
</Popover>
|
|
125
123
|
</>
|
|
126
124
|
);
|
|
@@ -136,7 +134,7 @@ const DynamicSettings = ( { controls }: { controls: DynamicTag[ 'atomic_controls
|
|
|
136
134
|
}
|
|
137
135
|
|
|
138
136
|
return (
|
|
139
|
-
|
|
137
|
+
<PopoverScrollableContent>
|
|
140
138
|
<Tabs size="small" variant="fullWidth" { ...getTabsProps() }>
|
|
141
139
|
{ tabs.map( ( { value }, index ) => (
|
|
142
140
|
<Tab key={ index } label={ value.label } sx={ { px: 1, py: 0.5 } } { ...getTabProps( index ) } />
|
|
@@ -147,18 +145,18 @@ const DynamicSettings = ( { controls }: { controls: DynamicTag[ 'atomic_controls
|
|
|
147
145
|
{ tabs.map( ( { value }, index ) => {
|
|
148
146
|
return (
|
|
149
147
|
<TabPanel key={ index } sx={ { flexGrow: 1, py: 0 } } { ...getTabPanelProps( index ) }>
|
|
150
|
-
<
|
|
148
|
+
<Stack p={ 2 } gap={ 2 }>
|
|
151
149
|
{ value.items.map( ( item ) => {
|
|
152
150
|
if ( item.type === 'control' ) {
|
|
153
151
|
return <Control key={ item.value.bind } control={ item.value } />;
|
|
154
152
|
}
|
|
155
153
|
return null;
|
|
156
154
|
} ) }
|
|
157
|
-
</
|
|
155
|
+
</Stack>
|
|
158
156
|
</TabPanel>
|
|
159
157
|
);
|
|
160
158
|
} ) }
|
|
161
|
-
|
|
159
|
+
</PopoverScrollableContent>
|
|
162
160
|
);
|
|
163
161
|
};
|
|
164
162
|
|