@elementor/editor-editing-panel 1.1.0 → 1.2.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.
@@ -1,82 +1,109 @@
1
1
  import * as React from 'react';
2
+ import { type JSX } from 'react';
2
3
  import { ControlLabel, type ToggleButtonGroupItem, ToggleControl } from '@elementor/editor-controls';
3
4
  import {
4
5
  JustifyBottomIcon,
5
- JustifyCenterIcon,
6
- JustifyDistributeVerticalIcon,
7
- JustifySpaceAroundVerticalIcon,
8
- JustifySpaceBetweenVerticalIcon,
6
+ JustifyCenterIcon as CenterIcon,
7
+ JustifyDistributeVerticalIcon as EvenlyIcon,
8
+ JustifySpaceAroundVerticalIcon as AroundIcon,
9
+ JustifySpaceBetweenVerticalIcon as BetweenIcon,
9
10
  JustifyTopIcon,
10
11
  } from '@elementor/icons';
11
- import { Stack } from '@elementor/ui';
12
+ import {
13
+ DirectionProvider,
14
+ Stack,
15
+ ThemeProvider,
16
+ type ToggleButtonProps,
17
+ useTheme,
18
+ withDirection,
19
+ } from '@elementor/ui';
12
20
  import { __ } from '@wordpress/i18n';
13
21
 
14
22
  import { StylesField } from '../../../controls-registry/styles-field';
15
23
  import { useDirection } from '../../../hooks/use-direction';
16
24
  import { useStylesField } from '../../../hooks/use-styles-field';
17
- import { rotateFlexIcon } from './utils/rotate-flex-icon';
25
+ import { type FlexDirection } from './flex-direction-field';
18
26
 
19
27
  type JustifyContent = 'start' | 'center' | 'end' | 'space-between' | 'space-around' | 'space-evenly';
20
28
 
21
29
  export const JustifyContentField = () => {
22
- const [ direction ] = useStylesField( 'flex-direction' );
30
+ const options = useOptions(),
31
+ { isSiteRtl } = useDirection();
23
32
 
24
- const { isUiRtl, isSiteRtl } = useDirection(),
25
- sx = { transform: rotateFlexIcon( direction as string, -1 ) } as const,
26
- shouldReverseOrder = isSiteRtl !== isUiRtl;
33
+ return (
34
+ <DirectionProvider rtl={ isSiteRtl }>
35
+ <ThemeProvider>
36
+ <StylesField bind="justify-content">
37
+ <Stack gap={ 1 }>
38
+ <ControlLabel>{ __( 'Justify Content', 'elementor' ) }</ControlLabel>
39
+ <ToggleControl options={ options } fullWidth={ true } />
40
+ </Stack>
41
+ </StylesField>
42
+ </ThemeProvider>
43
+ </DirectionProvider>
44
+ );
45
+ };
27
46
 
28
- const StartIcon = isSiteRtl ? JustifyBottomIcon : JustifyTopIcon,
29
- EndIcon = isSiteRtl ? JustifyTopIcon : JustifyBottomIcon;
47
+ const useOptions = (): ToggleButtonGroupItem< JustifyContent >[] => {
48
+ const StartIcon = withDirection( JustifyTopIcon ),
49
+ EndIcon = withDirection( JustifyBottomIcon );
30
50
 
31
- const options: ToggleButtonGroupItem< JustifyContent >[] = [
51
+ return [
32
52
  {
33
53
  value: 'start',
34
54
  label: __( 'Start', 'elementor' ),
35
- renderContent: ( { size } ) => <StartIcon fontSize={ size } sx={ sx } />,
55
+ renderContent: ( { size } ) => <RotatedIcon icon={ StartIcon } size={ size } />,
36
56
  showTooltip: true,
37
57
  },
38
58
  {
39
59
  value: 'center',
40
60
  label: __( 'Center', 'elementor' ),
41
- renderContent: ( { size } ) => <JustifyCenterIcon fontSize={ size } sx={ sx } />,
61
+ renderContent: ( { size } ) => <RotatedIcon icon={ CenterIcon } size={ size } />,
42
62
  showTooltip: true,
43
63
  },
44
64
  {
45
65
  value: 'end',
46
66
  label: __( 'End', 'elementor' ),
47
- renderContent: ( { size } ) => <EndIcon fontSize={ size } sx={ sx } />,
67
+ renderContent: ( { size } ) => <RotatedIcon icon={ EndIcon } size={ size } />,
48
68
  showTooltip: true,
49
69
  },
50
70
  {
51
71
  value: 'space-between',
52
- label: __( 'Space Between', 'elementor' ),
53
- renderContent: ( { size } ) => <JustifySpaceBetweenVerticalIcon fontSize={ size } sx={ sx } />,
72
+ label: __( 'Space between', 'elementor' ),
73
+ renderContent: ( { size } ) => <RotatedIcon icon={ BetweenIcon } size={ size } />,
54
74
  showTooltip: true,
55
75
  },
56
76
  {
57
77
  value: 'space-around',
58
- label: __( 'Space Around', 'elementor' ),
59
- renderContent: ( { size } ) => <JustifySpaceAroundVerticalIcon fontSize={ size } sx={ sx } />,
78
+ label: __( 'Space around', 'elementor' ),
79
+ renderContent: ( { size } ) => <RotatedIcon icon={ AroundIcon } size={ size } />,
60
80
  showTooltip: true,
61
81
  },
62
82
  {
63
83
  value: 'space-evenly',
64
- label: __( 'Space Evenly', 'elementor' ),
65
- renderContent: ( { size } ) => <JustifyDistributeVerticalIcon fontSize={ size } sx={ sx } />,
84
+ label: __( 'Space evenly', 'elementor' ),
85
+ renderContent: ( { size } ) => <RotatedIcon icon={ EvenlyIcon } size={ size } />,
66
86
  showTooltip: true,
67
87
  },
68
88
  ];
89
+ };
90
+
91
+ const RotatedIcon = ( { icon: Icon, size }: { icon: JSX.ElementType; size: ToggleButtonProps[ 'size' ] } ) => {
92
+ const [ direction ] = useStylesField< FlexDirection >( 'flex-direction' ),
93
+ isRtl = 'rtl' === useTheme().direction,
94
+ rotationMultiplier = isRtl ? -1 : 1;
69
95
 
70
- if ( shouldReverseOrder ) {
71
- options.reverse();
72
- }
96
+ const rotationAngelMap: Record< FlexDirection, number > = {
97
+ row: -90,
98
+ column: 0,
99
+ 'row-reverse': 90,
100
+ 'column-reverse': 180,
101
+ };
73
102
 
74
103
  return (
75
- <StylesField bind="justify-content">
76
- <Stack gap={ 1 }>
77
- <ControlLabel>{ __( 'Justify Content', 'elementor' ) }</ControlLabel>
78
- <ToggleControl options={ options } fullWidth={ true } />
79
- </Stack>
80
- </StylesField>
104
+ <Icon
105
+ fontSize={ size }
106
+ sx={ { transition: '.3s', rotate: `${ rotationAngelMap[ direction || 'row' ] * rotationMultiplier }deg` } }
107
+ />
81
108
  );
82
109
  };
@@ -1,9 +1,15 @@
1
1
  import * as React from 'react';
2
- import { Stack } from '@elementor/ui';
2
+ import { ControlLabel } from '@elementor/editor-controls';
3
+ import { Divider, Stack } from '@elementor/ui';
4
+ import { __ } from '@wordpress/i18n';
3
5
 
4
6
  import { useStylesField } from '../../../hooks/use-styles-field';
7
+ import { AlignItemsField } from './align-items-field';
5
8
  import { DisplayField } from './display-field';
9
+ import { FlexDirectionField } from './flex-direction-field';
10
+ import { FlexOrderField } from './flex-order-field';
6
11
  import { JustifyContentField } from './justify-content-field';
12
+ import { WrapField } from './wrap-field';
7
13
 
8
14
  export const LayoutSection = () => {
9
15
  const [ display ] = useStylesField( 'display' );
@@ -11,7 +17,20 @@ export const LayoutSection = () => {
11
17
  return (
12
18
  <Stack gap={ 2 }>
13
19
  <DisplayField />
14
- { 'flex' === display && <JustifyContentField /> }
20
+ { 'flex' === display && <FlexFields /> }
15
21
  </Stack>
16
22
  );
17
23
  };
24
+
25
+ const FlexFields = () => (
26
+ <>
27
+ <FlexDirectionField />
28
+ <JustifyContentField />
29
+ <AlignItemsField />
30
+ <Divider />
31
+ <WrapField />
32
+ <Divider />
33
+ <ControlLabel>{ __( 'Flex child', 'elementor' ) }</ControlLabel>
34
+ <FlexOrderField />
35
+ </>
36
+ );
@@ -0,0 +1,52 @@
1
+ import * as React from 'react';
2
+ import { ControlLabel, type ToggleButtonGroupItem, ToggleControl } from '@elementor/editor-controls';
3
+ import { ArrowBackIcon, ArrowForwardIcon, ArrowRightIcon } from '@elementor/icons';
4
+ import { DirectionProvider, Grid, ThemeProvider } from '@elementor/ui';
5
+ import { __ } from '@wordpress/i18n';
6
+
7
+ import { StylesField } from '../../../controls-registry/styles-field';
8
+ import { useDirection } from '../../../hooks/use-direction';
9
+
10
+ type FlexWrap = 'nowrap' | 'wrap' | 'wrap-reverse';
11
+
12
+ const options: ToggleButtonGroupItem< FlexWrap >[] = [
13
+ {
14
+ value: 'nowrap',
15
+ label: __( 'No wrap', 'elementor' ),
16
+ renderContent: ( { size } ) => <ArrowRightIcon fontSize={ size } />,
17
+ showTooltip: true,
18
+ },
19
+ {
20
+ value: 'wrap',
21
+ label: __( 'Wrap', 'elementor' ),
22
+ renderContent: ( { size } ) => <ArrowBackIcon fontSize={ size } />,
23
+ showTooltip: true,
24
+ },
25
+ {
26
+ value: 'wrap-reverse',
27
+ label: __( 'Wrap reverse', 'elementor' ),
28
+ renderContent: ( { size } ) => <ArrowForwardIcon fontSize={ size } />,
29
+ showTooltip: true,
30
+ },
31
+ ];
32
+
33
+ export const WrapField = () => {
34
+ const { isSiteRtl } = useDirection();
35
+
36
+ return (
37
+ <DirectionProvider rtl={ isSiteRtl }>
38
+ <ThemeProvider>
39
+ <StylesField bind={ 'flex-wrap' }>
40
+ <Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
41
+ <Grid item xs={ 6 }>
42
+ <ControlLabel>{ __( 'Wrap', 'elementor' ) }</ControlLabel>
43
+ </Grid>
44
+ <Grid item xs={ 6 } sx={ { display: 'flex', justifyContent: 'flex-end' } }>
45
+ <ToggleControl options={ options } />
46
+ </Grid>
47
+ </Grid>
48
+ </StylesField>
49
+ </ThemeProvider>
50
+ </DirectionProvider>
51
+ );
52
+ };
@@ -1,16 +1,51 @@
1
1
  import * as React from 'react';
2
- import { ControlLabel, StrokeControl } from '@elementor/editor-controls';
2
+ import { StrokeControl } from '@elementor/editor-controls';
3
3
  import { __ } from '@wordpress/i18n';
4
4
 
5
5
  import { StylesField } from '../../../controls-registry/styles-field';
6
- import { CollapsibleField } from '../../collapsible-field';
6
+ import { useStylesField } from '../../../hooks/use-styles-field';
7
+ import { AddOrRemoveContent } from '../../add-or-remove-content';
8
+
9
+ const initTextStroke = {
10
+ $$type: 'stroke',
11
+ value: {
12
+ color: {
13
+ $$type: 'color',
14
+ value: '#000000',
15
+ },
16
+ width: {
17
+ $$type: 'size',
18
+ value: {
19
+ unit: 'px',
20
+ size: 1,
21
+ },
22
+ },
23
+ },
24
+ };
7
25
 
8
26
  export const TextStrokeField = () => {
27
+ const [ textStroke, setTextStroke ] = useStylesField( '-webkit-text-stroke' );
28
+
29
+ const addTextStroke = () => {
30
+ setTextStroke( initTextStroke );
31
+ };
32
+
33
+ const removeTextStroke = () => {
34
+ setTextStroke( null );
35
+ };
36
+
37
+ const hasTextStroke = Boolean( textStroke );
38
+
9
39
  return (
10
- <StylesField bind="-webkit-text-stroke">
11
- <CollapsibleField label={ <ControlLabel>{ __( 'Text Stroke', 'elementor' ) }</ControlLabel> }>
40
+ <AddOrRemoveContent
41
+ label={ __( 'Text Stroke', 'elementor' ) }
42
+ isAdded={ hasTextStroke }
43
+ onAdd={ addTextStroke }
44
+ onRemove={ removeTextStroke }
45
+ >
46
+ <StylesField bind={ '-webkit-text-stroke' }>
12
47
  <StrokeControl />
13
- </CollapsibleField>
14
- </StylesField>
48
+ </StylesField>
49
+ </AddOrRemoveContent>
15
50
  );
16
51
  };
@@ -10,7 +10,7 @@ import { __ } from '@wordpress/i18n';
10
10
  import { ClassesPropProvider } from '../contexts/classes-prop-context';
11
11
  import { useElement } from '../contexts/element-context';
12
12
  import { StyleProvider } from '../contexts/style-context';
13
- import { CssClassSelectorSection } from './css-class-selector-section';
13
+ import { CssClassSelector } from './css-class-selector';
14
14
  import { Section } from './section';
15
15
  import { SectionsList } from './sections-list';
16
16
  import { BackgroundSection } from './style-sections/background-section/background-section';
@@ -32,7 +32,7 @@ export const StyleTab = () => {
32
32
  return (
33
33
  <ClassesPropProvider prop={ currentClassesProp }>
34
34
  <StyleProvider meta={ { breakpoint, state: null } } id={ activeStyleDefId } setId={ setActiveStyleDefId }>
35
- <CssClassSelectorSection />
35
+ <CssClassSelector />
36
36
  <Divider />
37
37
  <SectionsList>
38
38
  <Section title={ __( 'Layout', 'elementor' ) }>
@@ -1,76 +0,0 @@
1
- import * as React from 'react';
2
- import { useElementSetting, useElementStyles } from '@elementor/editor-elements';
3
- import { type ClassesPropValue } from '@elementor/editor-props';
4
- import { Chip, Stack, Typography } from '@elementor/ui';
5
- import { __ } from '@wordpress/i18n';
6
-
7
- import { useClassesProp } from '../contexts/classes-prop-context';
8
- import { useElement } from '../contexts/element-context';
9
- import { useStyle } from '../contexts/style-context';
10
- import { MultiCombobox, type Option } from './multi-combobox';
11
-
12
- const ID = 'elementor-css-class-selector';
13
- const TAGS_LIMIT = 8;
14
-
15
- export function CssClassSelectorSection() {
16
- const options = useOptions();
17
-
18
- const { id: activeId, setId: setActiveId } = useStyle();
19
- const appliedIds = useAppliedClassesIds();
20
-
21
- const applied = options.filter( ( option ) => appliedIds.includes( option.value ) );
22
- const active = options.find( ( option ) => option.value === activeId ) || null;
23
-
24
- return (
25
- <Stack gap={ 1 } p={ 2 }>
26
- <Typography component="label" variant="caption" htmlFor={ ID }>
27
- { __( 'CSS Classes', 'elementor' ) }
28
- </Typography>
29
- <MultiCombobox
30
- id={ ID }
31
- size="tiny"
32
- options={ options }
33
- selected={ applied }
34
- limitTags={ TAGS_LIMIT }
35
- optionsLabel={ __( 'Global CSS Classes', 'elementor' ) }
36
- renderTags={ ( tagValue, getTagProps ) =>
37
- tagValue.map( ( option, index ) => {
38
- const chipProps = getTagProps( { index } );
39
-
40
- return (
41
- <Chip
42
- { ...chipProps }
43
- key={ chipProps.key }
44
- size="small"
45
- label={ option.label }
46
- variant={ option.value === active?.value ? 'filled' : 'standard' }
47
- color={ option.color ?? 'default' }
48
- onClick={ () => setActiveId( option.value ) }
49
- onDelete={ null }
50
- />
51
- );
52
- } )
53
- }
54
- />
55
- </Stack>
56
- );
57
- }
58
-
59
- function useAppliedClassesIds() {
60
- const { element } = useElement();
61
- const currentClassesProp = useClassesProp();
62
-
63
- return useElementSetting< ClassesPropValue >( element.id, currentClassesProp )?.value || [];
64
- }
65
-
66
- function useOptions() {
67
- const { element } = useElement();
68
-
69
- const styleDefs = useElementStyles( element.id );
70
-
71
- return Object.values( styleDefs ).map< Option >( ( styleDef ) => ( {
72
- label: styleDef.label,
73
- value: styleDef.id,
74
- color: 'primary',
75
- } ) );
76
- }
@@ -1,12 +0,0 @@
1
- export function rotateFlexIcon( direction: string | null = 'row', initValue: number ) {
2
- const rotationIndexMap: Record< string, number > = {
3
- row: 0,
4
- column: 1,
5
- 'row-reverse': 2,
6
- 'column-reverse': 3,
7
- };
8
-
9
- const rotationIndex = initValue + ( rotationIndexMap[ direction || 'row' ] ?? 0 );
10
-
11
- return `rotate(calc(90deg * ${ rotationIndex }))`;
12
- }