@elementor/editor-editing-panel 4.1.0-manual → 4.2.0-839
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 +169 -1
- package/dist/index.d.ts +169 -1
- package/dist/index.js +1301 -857
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1145 -683
- package/dist/index.mjs.map +1 -1
- package/package.json +25 -22
- package/src/components/css-classes/use-apply-and-unapply-class.ts +10 -0
- package/src/components/design-system-import/components/conflict-options.tsx +67 -0
- package/src/components/design-system-import/components/trigger-button.tsx +33 -0
- package/src/components/design-system-import/hooks/use-dialog-state.ts +24 -0
- package/src/components/design-system-import/hooks/use-import-request.ts +38 -0
- package/src/components/design-system-import/import-design-system-dialog.tsx +89 -0
- package/src/components/design-system-import/import-notifications.tsx +57 -0
- package/src/components/design-system-import/types.ts +1 -0
- package/src/components/promotions/init.tsx +6 -7
- package/src/components/section-content.tsx +9 -2
- package/src/components/style-sections/layout-section/align-self-grid-child-field.tsx +74 -0
- package/src/components/style-sections/layout-section/display-field.tsx +21 -8
- package/src/components/style-sections/layout-section/grid-auto-flow-field.tsx +102 -0
- package/src/components/style-sections/layout-section/grid-justify-items-field.tsx +58 -0
- package/src/components/style-sections/layout-section/grid-size-field.tsx +96 -0
- package/src/components/style-sections/layout-section/grid-span-field.tsx +78 -0
- package/src/components/style-sections/layout-section/layout-section.tsx +50 -2
- package/src/components/style-sections/position-section/position-field.tsx +2 -6
- package/src/components/style-sections/position-section/position-section.tsx +82 -85
- package/src/components/style-sections/position-section/z-index-field.tsx +29 -3
- package/src/components/style-tab.tsx +3 -0
- package/src/contexts/styles-inheritance-context.tsx +16 -2
- package/src/controls-registry/conditional-field.tsx +84 -7
- package/src/controls-registry/controls-registry.tsx +16 -0
- package/src/hooks/use-styles-fields.ts +1 -1
- package/src/utils/prop-dependency-utils.ts +88 -12
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ControlToggleButtonGroup, type ToggleButtonGroupItem } from '@elementor/editor-controls';
|
|
3
|
+
import { type StringPropValue } from '@elementor/editor-props';
|
|
4
|
+
import { ArrowDownSmallIcon, ArrowRightIcon, LayoutDashboardIcon } from '@elementor/icons';
|
|
5
|
+
import { Grid, ToggleButton, Tooltip, withDirection } from '@elementor/ui';
|
|
6
|
+
import { __ } from '@wordpress/i18n';
|
|
7
|
+
|
|
8
|
+
import { StylesField } from '../../../controls-registry/styles-field';
|
|
9
|
+
import { useStylesField } from '../../../hooks/use-styles-field';
|
|
10
|
+
import { UiProviders } from '../../../styles-inheritance/components/ui-providers';
|
|
11
|
+
import { StylesFieldLayout } from '../../styles-field-layout';
|
|
12
|
+
|
|
13
|
+
type AutoFlowDirection = 'row' | 'column';
|
|
14
|
+
|
|
15
|
+
const AUTO_FLOW_LABEL = __( 'Auto flow', 'elementor' );
|
|
16
|
+
const DENSE_LABEL = __( 'Dense', 'elementor' );
|
|
17
|
+
|
|
18
|
+
const StartIcon = withDirection( ArrowRightIcon );
|
|
19
|
+
|
|
20
|
+
const directionOptions: ToggleButtonGroupItem< AutoFlowDirection >[] = [
|
|
21
|
+
{
|
|
22
|
+
value: 'row',
|
|
23
|
+
label: __( 'Row', 'elementor' ),
|
|
24
|
+
renderContent: ( { size } ) => <StartIcon fontSize={ size } />,
|
|
25
|
+
showTooltip: true,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
value: 'column',
|
|
29
|
+
label: __( 'Column', 'elementor' ),
|
|
30
|
+
renderContent: ( { size } ) => <ArrowDownSmallIcon fontSize={ size } />,
|
|
31
|
+
showTooltip: true,
|
|
32
|
+
},
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
const parseAutoFlow = ( value: string | null ): { direction: AutoFlowDirection; dense: boolean } => {
|
|
36
|
+
if ( ! value ) {
|
|
37
|
+
return { direction: 'row', dense: false };
|
|
38
|
+
}
|
|
39
|
+
const dense = value.includes( 'dense' );
|
|
40
|
+
const direction = value.replace( /\s*dense\s*/, '' ).trim() as AutoFlowDirection;
|
|
41
|
+
return { direction: direction || 'row', dense };
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const composeAutoFlow = ( direction: AutoFlowDirection, dense: boolean ): string => {
|
|
45
|
+
return dense ? `${ direction } dense` : direction;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const GridAutoFlowFieldContent = () => {
|
|
49
|
+
const { value, setValue } = useStylesField< StringPropValue | null >( 'grid-auto-flow', {
|
|
50
|
+
history: { propDisplayName: AUTO_FLOW_LABEL },
|
|
51
|
+
} );
|
|
52
|
+
|
|
53
|
+
const { direction, dense } = parseAutoFlow( value?.value ?? null );
|
|
54
|
+
|
|
55
|
+
const handleDirectionChange = ( newDirection: AutoFlowDirection | null ) => {
|
|
56
|
+
if ( ! newDirection ) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
setValue( { $$type: 'string', value: composeAutoFlow( newDirection, dense ) } );
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const handleDenseToggle = () => {
|
|
63
|
+
setValue( { $$type: 'string', value: composeAutoFlow( direction, ! dense ) } );
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<StylesFieldLayout label={ AUTO_FLOW_LABEL }>
|
|
68
|
+
<Grid container gap={ 1 } flexWrap="nowrap" alignItems="center" justifyContent="flex-end">
|
|
69
|
+
<Grid item sx={ { width: 64, maxWidth: '100%' } }>
|
|
70
|
+
<ControlToggleButtonGroup
|
|
71
|
+
items={ directionOptions }
|
|
72
|
+
value={ direction }
|
|
73
|
+
onChange={ handleDirectionChange }
|
|
74
|
+
exclusive={ true }
|
|
75
|
+
fullWidth={ true }
|
|
76
|
+
/>
|
|
77
|
+
</Grid>
|
|
78
|
+
<Grid item>
|
|
79
|
+
<Tooltip title={ DENSE_LABEL }>
|
|
80
|
+
<ToggleButton
|
|
81
|
+
value="dense"
|
|
82
|
+
selected={ dense }
|
|
83
|
+
onChange={ handleDenseToggle }
|
|
84
|
+
size="tiny"
|
|
85
|
+
aria-label={ DENSE_LABEL }
|
|
86
|
+
>
|
|
87
|
+
<LayoutDashboardIcon fontSize="tiny" />
|
|
88
|
+
</ToggleButton>
|
|
89
|
+
</Tooltip>
|
|
90
|
+
</Grid>
|
|
91
|
+
</Grid>
|
|
92
|
+
</StylesFieldLayout>
|
|
93
|
+
);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export const GridAutoFlowField = () => (
|
|
97
|
+
<StylesField bind="grid-auto-flow" propDisplayName={ AUTO_FLOW_LABEL }>
|
|
98
|
+
<UiProviders>
|
|
99
|
+
<GridAutoFlowFieldContent />
|
|
100
|
+
</UiProviders>
|
|
101
|
+
</StylesField>
|
|
102
|
+
);
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type ToggleButtonGroupItem, ToggleControl } from '@elementor/editor-controls';
|
|
3
|
+
import {
|
|
4
|
+
LayoutAlignCenterIcon as CenterIcon,
|
|
5
|
+
LayoutAlignLeftIcon,
|
|
6
|
+
LayoutAlignRightIcon,
|
|
7
|
+
LayoutDistributeVerticalIcon as StretchIcon,
|
|
8
|
+
} from '@elementor/icons';
|
|
9
|
+
import { withDirection } from '@elementor/ui';
|
|
10
|
+
import { __ } from '@wordpress/i18n';
|
|
11
|
+
|
|
12
|
+
import { StylesField } from '../../../controls-registry/styles-field';
|
|
13
|
+
import { UiProviders } from '../../../styles-inheritance/components/ui-providers';
|
|
14
|
+
import { StylesFieldLayout } from '../../styles-field-layout';
|
|
15
|
+
|
|
16
|
+
type JustifyItems = 'start' | 'center' | 'end' | 'stretch';
|
|
17
|
+
|
|
18
|
+
const JUSTIFY_ITEMS_LABEL = __( 'Justify items', 'elementor' );
|
|
19
|
+
|
|
20
|
+
const StartIcon = withDirection( LayoutAlignLeftIcon );
|
|
21
|
+
const EndIcon = withDirection( LayoutAlignRightIcon );
|
|
22
|
+
|
|
23
|
+
const options: ToggleButtonGroupItem< JustifyItems >[] = [
|
|
24
|
+
{
|
|
25
|
+
value: 'start',
|
|
26
|
+
label: __( 'Start', 'elementor' ),
|
|
27
|
+
renderContent: ( { size } ) => <StartIcon fontSize={ size } />,
|
|
28
|
+
showTooltip: true,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
value: 'center',
|
|
32
|
+
label: __( 'Center', 'elementor' ),
|
|
33
|
+
renderContent: ( { size } ) => <CenterIcon fontSize={ size } />,
|
|
34
|
+
showTooltip: true,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
value: 'end',
|
|
38
|
+
label: __( 'End', 'elementor' ),
|
|
39
|
+
renderContent: ( { size } ) => <EndIcon fontSize={ size } />,
|
|
40
|
+
showTooltip: true,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
value: 'stretch',
|
|
44
|
+
label: __( 'Stretch', 'elementor' ),
|
|
45
|
+
renderContent: ( { size } ) => <StretchIcon fontSize={ size } />,
|
|
46
|
+
showTooltip: true,
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
export const GridJustifyItemsField = () => (
|
|
51
|
+
<StylesField bind="justify-items" propDisplayName={ JUSTIFY_ITEMS_LABEL }>
|
|
52
|
+
<UiProviders>
|
|
53
|
+
<StylesFieldLayout label={ JUSTIFY_ITEMS_LABEL }>
|
|
54
|
+
<ToggleControl options={ options } />
|
|
55
|
+
</StylesFieldLayout>
|
|
56
|
+
</UiProviders>
|
|
57
|
+
</StylesField>
|
|
58
|
+
);
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useRef } from 'react';
|
|
3
|
+
import { SizeComponent } from '@elementor/editor-controls';
|
|
4
|
+
import { type StringPropValue } from '@elementor/editor-props';
|
|
5
|
+
import { Grid } from '@elementor/ui';
|
|
6
|
+
import { __ } from '@wordpress/i18n';
|
|
7
|
+
|
|
8
|
+
import { StylesField } from '../../../controls-registry/styles-field';
|
|
9
|
+
import { useStylesField } from '../../../hooks/use-styles-field';
|
|
10
|
+
import { StylesFieldLayout } from '../../styles-field-layout';
|
|
11
|
+
|
|
12
|
+
type GridTrackUnit = 'fr' | 'custom';
|
|
13
|
+
type GridTrackValue = { size: number | string; unit: GridTrackUnit };
|
|
14
|
+
|
|
15
|
+
const FR = 'fr' as const;
|
|
16
|
+
const CUSTOM = 'custom' as const;
|
|
17
|
+
const UNITS: GridTrackUnit[] = [ FR, CUSTOM ];
|
|
18
|
+
|
|
19
|
+
const REPEAT_FR_PATTERN = /^repeat\(\s*(\d+)\s*,\s*1fr\s*\)$/;
|
|
20
|
+
|
|
21
|
+
const cssToTrackValue = ( css: string | null ): GridTrackValue | null => {
|
|
22
|
+
if ( ! css ) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const match = css.match( REPEAT_FR_PATTERN );
|
|
26
|
+
if ( match ) {
|
|
27
|
+
return { size: parseInt( match[ 1 ], 10 ), unit: FR };
|
|
28
|
+
}
|
|
29
|
+
return { size: css, unit: CUSTOM };
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const trackValueToCss = ( trackValue: GridTrackValue | null ): string | null => {
|
|
33
|
+
if ( ! trackValue || trackValue.size === '' || trackValue.size === null ) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
if ( trackValue.unit === FR ) {
|
|
37
|
+
return `repeat(${ trackValue.size }, 1fr)`;
|
|
38
|
+
}
|
|
39
|
+
return String( trackValue.size );
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
type GridTrackCssProp = 'grid-template-rows' | 'grid-template-columns';
|
|
43
|
+
|
|
44
|
+
type GridTrackFieldProps = {
|
|
45
|
+
cssProp: GridTrackCssProp;
|
|
46
|
+
label: string;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const GridTrackField = ( { cssProp, label }: GridTrackFieldProps ) => (
|
|
50
|
+
<StylesField bind={ cssProp } propDisplayName={ label }>
|
|
51
|
+
<GridTrackFieldContent cssProp={ cssProp } label={ label } />
|
|
52
|
+
</StylesField>
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
const GridTrackFieldContent = ( { cssProp, label }: GridTrackFieldProps ) => {
|
|
56
|
+
const { value, setValue } = useStylesField< StringPropValue | null >( cssProp, {
|
|
57
|
+
history: { propDisplayName: label },
|
|
58
|
+
} );
|
|
59
|
+
|
|
60
|
+
const anchorRef = useRef< HTMLDivElement >( null );
|
|
61
|
+
const trackValue = cssToTrackValue( value?.value ?? null );
|
|
62
|
+
|
|
63
|
+
const handleChange = ( newValue: GridTrackValue ) => {
|
|
64
|
+
const css = trackValueToCss( newValue );
|
|
65
|
+
setValue( css ? { $$type: 'string', value: css } : null );
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<StylesFieldLayout label={ label } direction="column">
|
|
70
|
+
<div ref={ anchorRef }>
|
|
71
|
+
<SizeComponent
|
|
72
|
+
units={ UNITS as unknown as Parameters< typeof SizeComponent >[ 0 ][ 'units' ] }
|
|
73
|
+
value={
|
|
74
|
+
( trackValue ?? { size: NaN, unit: FR } ) as Parameters< typeof SizeComponent >[ 0 ][ 'value' ]
|
|
75
|
+
}
|
|
76
|
+
defaultUnit={ FR as Parameters< typeof SizeComponent >[ 0 ][ 'defaultUnit' ] }
|
|
77
|
+
setValue={ handleChange as Parameters< typeof SizeComponent >[ 0 ][ 'setValue' ] }
|
|
78
|
+
onBlur={ () => {} }
|
|
79
|
+
min={ 1 }
|
|
80
|
+
anchorRef={ anchorRef }
|
|
81
|
+
/>
|
|
82
|
+
</div>
|
|
83
|
+
</StylesFieldLayout>
|
|
84
|
+
);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export const GridSizeFields = () => (
|
|
88
|
+
<Grid container gap={ 2 } flexWrap="nowrap">
|
|
89
|
+
<Grid item xs={ 6 }>
|
|
90
|
+
<GridTrackField cssProp="grid-template-columns" label={ __( 'Columns', 'elementor' ) } />
|
|
91
|
+
</Grid>
|
|
92
|
+
<Grid item xs={ 6 }>
|
|
93
|
+
<GridTrackField cssProp="grid-template-rows" label={ __( 'Rows', 'elementor' ) } />
|
|
94
|
+
</Grid>
|
|
95
|
+
</Grid>
|
|
96
|
+
);
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { NumberInput } from '@elementor/editor-controls';
|
|
3
|
+
import { type SpanPropValue } from '@elementor/editor-props';
|
|
4
|
+
import { Grid } from '@elementor/ui';
|
|
5
|
+
import { __ } from '@wordpress/i18n';
|
|
6
|
+
|
|
7
|
+
import { StylesField } from '../../../controls-registry/styles-field';
|
|
8
|
+
import { useStylesField } from '../../../hooks/use-styles-field';
|
|
9
|
+
import { UiProviders } from '../../../styles-inheritance/components/ui-providers';
|
|
10
|
+
import { StylesFieldLayout } from '../../styles-field-layout';
|
|
11
|
+
|
|
12
|
+
type GridSpanCssProp = 'grid-column' | 'grid-row';
|
|
13
|
+
|
|
14
|
+
const MIN_SPAN = 1;
|
|
15
|
+
|
|
16
|
+
type GridSpanFieldProps = {
|
|
17
|
+
cssProp: GridSpanCssProp;
|
|
18
|
+
label: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const GridSpanFieldContent = ( { cssProp, label }: GridSpanFieldProps ) => {
|
|
22
|
+
const { value, setValue, canEdit } = useStylesField< SpanPropValue | null >( cssProp, {
|
|
23
|
+
history: { propDisplayName: label },
|
|
24
|
+
} );
|
|
25
|
+
|
|
26
|
+
const spanValue = value?.value ?? null;
|
|
27
|
+
|
|
28
|
+
const handleChange = ( event: React.ChangeEvent< HTMLInputElement > ) => {
|
|
29
|
+
const raw = event.target.value;
|
|
30
|
+
|
|
31
|
+
if ( raw === '' ) {
|
|
32
|
+
setValue( null );
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const num = parseInt( raw, 10 );
|
|
37
|
+
|
|
38
|
+
if ( Number.isNaN( num ) ) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const clamped = Math.max( num, MIN_SPAN );
|
|
43
|
+
setValue( { $$type: 'span', value: clamped } );
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<StylesFieldLayout label={ label } direction="column">
|
|
48
|
+
<NumberInput
|
|
49
|
+
size="tiny"
|
|
50
|
+
type="number"
|
|
51
|
+
fullWidth
|
|
52
|
+
disabled={ ! canEdit }
|
|
53
|
+
value={ spanValue ?? '' }
|
|
54
|
+
onInput={ handleChange }
|
|
55
|
+
inputProps={ { min: MIN_SPAN } }
|
|
56
|
+
/>
|
|
57
|
+
</StylesFieldLayout>
|
|
58
|
+
);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const GridSpanField = ( { cssProp, label }: GridSpanFieldProps ) => (
|
|
62
|
+
<StylesField bind={ cssProp } propDisplayName={ label }>
|
|
63
|
+
<UiProviders>
|
|
64
|
+
<GridSpanFieldContent cssProp={ cssProp } label={ label } />
|
|
65
|
+
</UiProviders>
|
|
66
|
+
</StylesField>
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
export const GridSpanFields = () => (
|
|
70
|
+
<Grid container gap={ 2 } flexWrap="nowrap">
|
|
71
|
+
<Grid item xs={ 6 }>
|
|
72
|
+
<GridSpanField cssProp="grid-column" label={ __( 'Column Span', 'elementor' ) } />
|
|
73
|
+
</Grid>
|
|
74
|
+
<Grid item xs={ 6 }>
|
|
75
|
+
<GridSpanField cssProp="grid-row" label={ __( 'Row Span', 'elementor' ) } />
|
|
76
|
+
</Grid>
|
|
77
|
+
</Grid>
|
|
78
|
+
);
|
|
@@ -2,6 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
import { ControlFormLabel } from '@elementor/editor-controls';
|
|
3
3
|
import { useParentElement } from '@elementor/editor-elements';
|
|
4
4
|
import { type StringPropValue } from '@elementor/editor-props';
|
|
5
|
+
import { isExperimentActive } from '@elementor/editor-v1-adapters';
|
|
5
6
|
import { __ } from '@wordpress/i18n';
|
|
6
7
|
|
|
7
8
|
import { useElement } from '../../../contexts/element-context';
|
|
@@ -12,33 +13,58 @@ import { SectionContent } from '../../section-content';
|
|
|
12
13
|
import { AlignContentField } from './align-content-field';
|
|
13
14
|
import { AlignItemsField } from './align-items-field';
|
|
14
15
|
import { AlignSelfChild } from './align-self-child-field';
|
|
16
|
+
import { AlignSelfGridChild } from './align-self-grid-child-field';
|
|
15
17
|
import { DisplayField, useDisplayPlaceholderValue } from './display-field';
|
|
16
18
|
import { type FlexDirection, FlexDirectionField } from './flex-direction-field';
|
|
17
19
|
import { FlexOrderField } from './flex-order-field';
|
|
18
20
|
import { FlexSizeField } from './flex-size-field';
|
|
19
21
|
import { GapControlField } from './gap-control-field';
|
|
22
|
+
import { GridAutoFlowField } from './grid-auto-flow-field';
|
|
23
|
+
import { GridJustifyItemsField } from './grid-justify-items-field';
|
|
24
|
+
import { GridSizeFields } from './grid-size-field';
|
|
25
|
+
import { GridSpanFields } from './grid-span-field';
|
|
20
26
|
import { JustifyContentField } from './justify-content-field';
|
|
21
27
|
import { WrapField } from './wrap-field';
|
|
22
28
|
|
|
23
29
|
const DISPLAY_LABEL = __( 'Display', 'elementor' );
|
|
24
30
|
const FLEX_WRAP_LABEL = __( 'Flex wrap', 'elementor' );
|
|
31
|
+
const DEFAULT_PARENT_FLOW_DIRECTION = 'row';
|
|
25
32
|
|
|
26
33
|
export const LayoutSection = () => {
|
|
27
34
|
const { value: display } = useStylesField< StringPropValue >( 'display', {
|
|
28
35
|
history: { propDisplayName: DISPLAY_LABEL },
|
|
29
36
|
} );
|
|
30
37
|
const displayPlaceholder = useDisplayPlaceholderValue();
|
|
38
|
+
const isGridExperimentActive = isExperimentActive( 'e_css_grid' );
|
|
31
39
|
const isDisplayFlex = shouldDisplayFlexFields( display, displayPlaceholder as StringPropValue );
|
|
40
|
+
const isDisplayGrid = 'grid' === ( display?.value ?? ( displayPlaceholder as StringPropValue )?.value );
|
|
32
41
|
const { element } = useElement();
|
|
33
42
|
const parent = useParentElement( element.id );
|
|
34
43
|
const parentStyle = useComputedStyle( parent?.id || null );
|
|
35
|
-
|
|
44
|
+
|
|
45
|
+
const getParentStyleDirection = () => {
|
|
46
|
+
if ( 'flex' === parentStyle?.display ) {
|
|
47
|
+
return parentStyle?.flexDirection ?? DEFAULT_PARENT_FLOW_DIRECTION;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if ( 'grid' === parentStyle?.display ) {
|
|
51
|
+
return parentStyle?.gridAutoFlow ?? DEFAULT_PARENT_FLOW_DIRECTION;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return DEFAULT_PARENT_FLOW_DIRECTION;
|
|
55
|
+
};
|
|
36
56
|
|
|
37
57
|
return (
|
|
38
58
|
<SectionContent>
|
|
39
59
|
<DisplayField />
|
|
40
60
|
{ isDisplayFlex && <FlexFields /> }
|
|
41
|
-
{ 'flex' === parentStyle?.display &&
|
|
61
|
+
{ 'flex' === parentStyle?.display && (
|
|
62
|
+
<FlexChildFields parentStyleDirection={ getParentStyleDirection() } />
|
|
63
|
+
) }
|
|
64
|
+
{ isGridExperimentActive && isDisplayGrid && <GridFields /> }
|
|
65
|
+
{ isGridExperimentActive && 'grid' === parentStyle?.display && (
|
|
66
|
+
<GridChildFields parentStyleDirection={ getParentStyleDirection() } />
|
|
67
|
+
) }
|
|
42
68
|
</SectionContent>
|
|
43
69
|
);
|
|
44
70
|
};
|
|
@@ -61,6 +87,18 @@ const FlexFields = () => {
|
|
|
61
87
|
);
|
|
62
88
|
};
|
|
63
89
|
|
|
90
|
+
const GridFields = () => (
|
|
91
|
+
<>
|
|
92
|
+
<GridSizeFields />
|
|
93
|
+
<GridAutoFlowField />
|
|
94
|
+
<PanelDivider />
|
|
95
|
+
<GapControlField />
|
|
96
|
+
<PanelDivider />
|
|
97
|
+
<GridJustifyItemsField />
|
|
98
|
+
<AlignItemsField />
|
|
99
|
+
</>
|
|
100
|
+
);
|
|
101
|
+
|
|
64
102
|
const FlexChildFields = ( { parentStyleDirection }: { parentStyleDirection: string } ) => (
|
|
65
103
|
<>
|
|
66
104
|
<PanelDivider />
|
|
@@ -71,6 +109,16 @@ const FlexChildFields = ( { parentStyleDirection }: { parentStyleDirection: stri
|
|
|
71
109
|
</>
|
|
72
110
|
);
|
|
73
111
|
|
|
112
|
+
const GridChildFields = ( { parentStyleDirection }: { parentStyleDirection: string } ) => (
|
|
113
|
+
<>
|
|
114
|
+
<PanelDivider />
|
|
115
|
+
<ControlFormLabel>{ __( 'Grid Child', 'elementor' ) }</ControlFormLabel>
|
|
116
|
+
<GridSpanFields />
|
|
117
|
+
<AlignSelfGridChild parentStyleDirection={ parentStyleDirection } />
|
|
118
|
+
<FlexOrderField />
|
|
119
|
+
</>
|
|
120
|
+
);
|
|
121
|
+
|
|
74
122
|
const shouldDisplayFlexFields = ( display: StringPropValue | null, local: StringPropValue ) => {
|
|
75
123
|
const value = display?.value ?? local?.value;
|
|
76
124
|
|
|
@@ -15,15 +15,11 @@ const positionOptions = [
|
|
|
15
15
|
{ label: __( 'Sticky', 'elementor' ), value: 'sticky' },
|
|
16
16
|
];
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
onChange?: ( newValue: string | null, previousValue: string | null | undefined ) => void;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export const PositionField = ( { onChange }: Props ) => {
|
|
18
|
+
export const PositionField = () => {
|
|
23
19
|
return (
|
|
24
20
|
<StylesField bind="position" propDisplayName={ POSITION_LABEL }>
|
|
25
21
|
<StylesFieldLayout label={ POSITION_LABEL }>
|
|
26
|
-
<SelectControl options={ positionOptions }
|
|
22
|
+
<SelectControl options={ positionOptions } />
|
|
27
23
|
</StylesFieldLayout>
|
|
28
24
|
</StylesField>
|
|
29
25
|
);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import { type StringPropValue } from '@elementor/editor-props';
|
|
2
|
+
import { useEffect, useRef } from 'react';
|
|
3
|
+
import { type NumberPropValue, type SizePropValue, type StringPropValue } from '@elementor/editor-props';
|
|
4
4
|
import { useSessionStorage } from '@elementor/session';
|
|
5
|
+
import { styled } from '@elementor/ui';
|
|
5
6
|
import { __ } from '@wordpress/i18n';
|
|
6
7
|
|
|
7
8
|
import { useStyle } from '../../../contexts/style-context';
|
|
@@ -14,112 +15,62 @@ import { OffsetField } from './offset-field';
|
|
|
14
15
|
import { PositionField } from './position-field';
|
|
15
16
|
import { ZIndexField } from './z-index-field';
|
|
16
17
|
|
|
17
|
-
type
|
|
18
|
-
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
|
23
|
-
| null;
|
|
24
|
-
|
|
25
|
-
type DimensionsValues = {
|
|
26
|
-
'inset-block-start': DimensionValue;
|
|
27
|
-
'inset-block-end': DimensionValue;
|
|
28
|
-
'inset-inline-start': DimensionValue;
|
|
29
|
-
'inset-inline-end': DimensionValue;
|
|
18
|
+
type DependentValues = {
|
|
19
|
+
'inset-block-start'?: SizePropValue | null;
|
|
20
|
+
'inset-block-end'?: SizePropValue | null;
|
|
21
|
+
'inset-inline-start'?: SizePropValue | null;
|
|
22
|
+
'inset-inline-end'?: SizePropValue | null;
|
|
23
|
+
'z-index'?: NumberPropValue | null;
|
|
30
24
|
};
|
|
31
25
|
|
|
32
|
-
|
|
33
|
-
'z-index': number | undefined | null;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const POSITION_STATIC = 'static' as const;
|
|
26
|
+
const POSITION_STATIC = 'static';
|
|
37
27
|
|
|
38
28
|
const POSITION_LABEL = __( 'Position', 'elementor' );
|
|
39
29
|
const DIMENSIONS_LABEL = __( 'Dimensions', 'elementor' );
|
|
40
30
|
|
|
41
|
-
const
|
|
31
|
+
const DEPENDENT_PROP_NAMES: Array< keyof DependentValues > = [
|
|
42
32
|
'inset-block-start',
|
|
43
33
|
'inset-block-end',
|
|
44
34
|
'inset-inline-start',
|
|
45
35
|
'inset-inline-end',
|
|
46
36
|
'z-index',
|
|
47
|
-
]
|
|
48
|
-
|
|
49
|
-
const CLEARED_POSITION_DEPENDENT_VALUES: Record< ( typeof POSITION_DEPENDENT_PROP_NAMES )[ number ], null > = {
|
|
50
|
-
'inset-block-start': null,
|
|
51
|
-
'inset-block-end': null,
|
|
52
|
-
'inset-inline-start': null,
|
|
53
|
-
'inset-inline-end': null,
|
|
54
|
-
'z-index': null,
|
|
55
|
-
};
|
|
37
|
+
];
|
|
56
38
|
|
|
57
39
|
export const PositionSection = () => {
|
|
58
|
-
const { value:
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const [ dimensionsValuesFromHistory, updateDimensionsHistory, clearDimensionsHistory ] = usePersistDimensions();
|
|
65
|
-
|
|
66
|
-
const clearPositionDependentProps = useCallback( () => {
|
|
67
|
-
const dimensions: DimensionsValues = {
|
|
68
|
-
'inset-block-start': positionDependentValues?.[ 'inset-block-start' ],
|
|
69
|
-
'inset-block-end': positionDependentValues?.[ 'inset-block-end' ],
|
|
70
|
-
'inset-inline-start': positionDependentValues?.[ 'inset-inline-start' ],
|
|
71
|
-
'inset-inline-end': positionDependentValues?.[ 'inset-inline-end' ],
|
|
72
|
-
};
|
|
73
|
-
const meta = { history: { propDisplayName: DIMENSIONS_LABEL } };
|
|
74
|
-
const hasValuesToClear =
|
|
75
|
-
Object.values( dimensions ).some( ( v ) => v !== null ) || positionDependentValues?.[ 'z-index' ] !== null;
|
|
40
|
+
const { value: position } = useStylesField< StringPropValue >( 'position', withHistoryLabel( POSITION_LABEL ) );
|
|
41
|
+
const positionPrevRef = useRef( position );
|
|
42
|
+
const { values: dependentValues, setValues: setDependentValues } =
|
|
43
|
+
useStylesFields< DependentValues >( DEPENDENT_PROP_NAMES );
|
|
44
|
+
|
|
45
|
+
const [ savedDependentValues, saveToHistory, clearHistory ] = usePersistDimensions();
|
|
76
46
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
47
|
+
useEffect( () => {
|
|
48
|
+
if ( position && position?.value === POSITION_STATIC && hasDependentValues( dependentValues ) ) {
|
|
49
|
+
saveToHistory( extractDimensions( dependentValues ) );
|
|
80
50
|
}
|
|
81
|
-
}, [ positionDependentValues, updateDimensionsHistory, setPositionDependentValues ] );
|
|
82
51
|
|
|
83
|
-
|
|
84
|
-
|
|
52
|
+
if ( positionPrevRef.current?.value === POSITION_STATIC ) {
|
|
53
|
+
setDependentValues( { ...savedDependentValues }, withHistoryLabel( DIMENSIONS_LABEL ) );
|
|
85
54
|
|
|
86
|
-
|
|
87
|
-
if ( positionValue?.value === POSITION_STATIC || positionValue === null ) {
|
|
88
|
-
clearPositionDependentPropsRef.current();
|
|
55
|
+
clearHistory();
|
|
89
56
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const meta = { history: { propDisplayName: DIMENSIONS_LABEL } };
|
|
94
|
-
|
|
95
|
-
if ( newPosition === POSITION_STATIC ) {
|
|
96
|
-
clearPositionDependentProps();
|
|
97
|
-
} else if ( previousPosition === POSITION_STATIC ) {
|
|
98
|
-
if ( dimensionsValuesFromHistory ) {
|
|
99
|
-
setPositionDependentValues(
|
|
100
|
-
{ ...dimensionsValuesFromHistory, 'z-index': undefined } as PositionDependentValues,
|
|
101
|
-
meta
|
|
102
|
-
);
|
|
103
|
-
clearDimensionsHistory();
|
|
104
|
-
}
|
|
57
|
+
|
|
58
|
+
if ( ( ! position || position?.value === POSITION_STATIC ) && dependentValues?.[ 'z-index' ] ) {
|
|
59
|
+
setDependentValues( { 'z-index': null }, withHistoryLabel( DIMENSIONS_LABEL ) );
|
|
105
60
|
}
|
|
106
|
-
};
|
|
107
61
|
|
|
108
|
-
|
|
62
|
+
positionPrevRef.current = position;
|
|
63
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
64
|
+
}, [ position?.value ] );
|
|
109
65
|
|
|
110
66
|
return (
|
|
111
|
-
<
|
|
112
|
-
<PositionField
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
<DimensionsField />
|
|
116
|
-
<ZIndexField />
|
|
117
|
-
</>
|
|
118
|
-
) : null }
|
|
119
|
-
|
|
67
|
+
<StyledSectionContent>
|
|
68
|
+
<PositionField />
|
|
69
|
+
<DimensionsField />
|
|
70
|
+
<ZIndexField disabled={ ! position || position?.value === POSITION_STATIC } />
|
|
120
71
|
<PanelDivider />
|
|
121
72
|
<OffsetField />
|
|
122
|
-
</
|
|
73
|
+
</StyledSectionContent>
|
|
123
74
|
);
|
|
124
75
|
};
|
|
125
76
|
|
|
@@ -128,5 +79,51 @@ const usePersistDimensions = () => {
|
|
|
128
79
|
const styleVariantPath = `styles/${ styleDefID }/${ meta.breakpoint || 'desktop' }/${ meta.state || 'null' }`;
|
|
129
80
|
const dimensionsPath = `${ styleVariantPath }/dimensions`;
|
|
130
81
|
|
|
131
|
-
return useSessionStorage<
|
|
82
|
+
return useSessionStorage< DependentValues >( dimensionsPath );
|
|
132
83
|
};
|
|
84
|
+
|
|
85
|
+
const withHistoryLabel = ( name: string ) => {
|
|
86
|
+
return {
|
|
87
|
+
history: { propDisplayName: name },
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const hasDependentValues = ( values?: DependentValues | null ) => {
|
|
92
|
+
if ( ! values ) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const dimensions = extractDimensions( values );
|
|
97
|
+
|
|
98
|
+
return Object.values( dimensions ).some( ( v ) => v !== null );
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const extractDimensions = ( values: DependentValues | null ): DependentValues => {
|
|
102
|
+
return DEPENDENT_PROP_NAMES.reduce( ( acc, key ) => {
|
|
103
|
+
return {
|
|
104
|
+
...acc,
|
|
105
|
+
[ key ]: values?.[ key ] ?? null,
|
|
106
|
+
};
|
|
107
|
+
}, {} );
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const StyledSectionContent = styled( SectionContent, {
|
|
111
|
+
shouldForwardProp: ( prop ) => prop !== 'gap',
|
|
112
|
+
} )< { gap?: number } >( ( { gap = 2, theme } ) => ( {
|
|
113
|
+
gap: 0,
|
|
114
|
+
'& > *': {
|
|
115
|
+
marginBottom: theme.spacing( gap ),
|
|
116
|
+
},
|
|
117
|
+
'& > *:last-child': {
|
|
118
|
+
marginBottom: 0,
|
|
119
|
+
},
|
|
120
|
+
'& > .MuiStack-root': {
|
|
121
|
+
marginBottom: 0,
|
|
122
|
+
},
|
|
123
|
+
'& > .MuiStack-root:has(> *)': {
|
|
124
|
+
marginBottom: theme.spacing( gap ),
|
|
125
|
+
},
|
|
126
|
+
'& > .MuiDivider-root': {
|
|
127
|
+
marginBottom: theme.spacing( gap ),
|
|
128
|
+
},
|
|
129
|
+
} ) );
|