@elementor/editor-editing-panel 0.19.0 → 1.1.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.
Files changed (139) hide show
  1. package/CHANGELOG.md +97 -0
  2. package/dist/index.d.mts +10 -36
  3. package/dist/index.d.ts +10 -36
  4. package/dist/index.js +1256 -1445
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +1311 -1482
  7. package/dist/index.mjs.map +1 -1
  8. package/package.json +15 -14
  9. package/src/components/add-or-remove-content.tsx +42 -0
  10. package/src/components/collapse-icon.tsx +12 -0
  11. package/src/components/collapsible-content.tsx +5 -14
  12. package/src/components/collapsible-field.tsx +36 -0
  13. package/src/components/css-class-selector-section.tsx +76 -0
  14. package/src/components/editing-panel-hooks.tsx +2 -0
  15. package/src/components/editing-panel-tabs.tsx +23 -13
  16. package/src/components/editing-panel.tsx +21 -21
  17. package/src/components/multi-combobox/index.ts +3 -0
  18. package/src/components/multi-combobox/multi-combobox.tsx +120 -0
  19. package/src/components/multi-combobox/types.ts +26 -0
  20. package/src/components/multi-combobox/use-combobox-actions.ts +62 -0
  21. package/src/components/section.tsx +37 -0
  22. package/src/components/sections-list.tsx +6 -0
  23. package/src/components/settings-tab.tsx +17 -16
  24. package/src/components/style-sections/background-section/background-color-field.tsx +21 -0
  25. package/src/components/style-sections/background-section/background-section.tsx +10 -8
  26. package/src/components/style-sections/border-section/border-color-field.tsx +21 -0
  27. package/src/components/style-sections/border-section/border-field.tsx +48 -0
  28. package/src/components/style-sections/border-section/border-radius-field.tsx +49 -0
  29. package/src/components/style-sections/border-section/border-section.tsx +13 -0
  30. package/src/components/style-sections/border-section/border-style-field.tsx +32 -0
  31. package/src/components/style-sections/border-section/border-width-field.tsx +43 -0
  32. package/src/components/style-sections/effects-section/effects-section.tsx +8 -11
  33. package/src/components/style-sections/layout-section/display-field.tsx +32 -0
  34. package/src/components/style-sections/layout-section/justify-content-field.tsx +82 -0
  35. package/src/components/style-sections/layout-section/layout-section.tsx +17 -0
  36. package/src/components/style-sections/layout-section/utils/rotate-flex-icon.ts +12 -0
  37. package/src/components/style-sections/position-section/dimensions-field.tsx +46 -0
  38. package/src/components/style-sections/position-section/position-field.tsx +28 -0
  39. package/src/components/style-sections/position-section/position-section.tsx +51 -8
  40. package/src/components/style-sections/position-section/z-index-field.tsx +21 -0
  41. package/src/components/style-sections/size-section/overflow-field.tsx +45 -0
  42. package/src/components/style-sections/size-section/size-section.tsx +62 -0
  43. package/src/components/style-sections/spacing-section/spacing-section.tsx +12 -14
  44. package/src/components/style-sections/typography-section/font-family-field.tsx +40 -0
  45. package/src/components/style-sections/typography-section/font-size-field.tsx +21 -0
  46. package/src/components/style-sections/typography-section/{font-weight-control.tsx → font-weight-field.tsx} +9 -8
  47. package/src/components/style-sections/typography-section/letter-spacing-field.tsx +21 -0
  48. package/src/components/style-sections/typography-section/text-alignment-field.tsx +47 -0
  49. package/src/components/style-sections/typography-section/text-color-field.tsx +21 -0
  50. package/src/components/style-sections/typography-section/{text-direction-control.tsx → text-direction-field.tsx} +12 -12
  51. package/src/components/style-sections/typography-section/text-stroke-field.tsx +16 -0
  52. package/src/components/style-sections/typography-section/{text-style-control.tsx → text-style-field.tsx} +9 -8
  53. package/src/components/style-sections/typography-section/transform-field.tsx +40 -0
  54. package/src/components/style-sections/typography-section/typography-section.tsx +31 -30
  55. package/src/components/style-sections/typography-section/word-spacing-field.tsx +21 -0
  56. package/src/components/style-tab.tsx +82 -29
  57. package/src/contexts/classes-prop-context.tsx +24 -0
  58. package/src/{controls/providers/element-provider.tsx → contexts/element-context.tsx} +3 -7
  59. package/src/contexts/style-context.tsx +10 -23
  60. package/src/control-replacement.tsx +1 -1
  61. package/src/{controls/control-actions/control-actions-menu.ts → controls-actions.ts} +2 -1
  62. package/src/{controls/components → controls-registry}/control-type-container.tsx +3 -2
  63. package/src/{controls → controls-registry}/control.tsx +2 -1
  64. package/src/{controls → controls-registry}/controls-registry.tsx +8 -6
  65. package/src/controls-registry/settings-field.tsx +36 -0
  66. package/src/controls-registry/styles-field.tsx +20 -0
  67. package/src/dynamics/components/dynamic-selection-control.tsx +18 -17
  68. package/src/dynamics/components/dynamic-selection.tsx +10 -9
  69. package/src/dynamics/dynamic-control.tsx +7 -6
  70. package/src/dynamics/hooks/use-dynamic-tag.ts +3 -2
  71. package/src/dynamics/hooks/use-prop-dynamic-action.tsx +7 -6
  72. package/src/dynamics/hooks/use-prop-dynamic-tags.ts +3 -2
  73. package/src/dynamics/init.ts +3 -3
  74. package/src/dynamics/sync/get-elementor-config.ts +1 -1
  75. package/src/dynamics/types.ts +2 -2
  76. package/src/dynamics/utils.ts +3 -3
  77. package/src/hooks/use-close-editor-panel.ts +23 -0
  78. package/src/hooks/use-direction.ts +13 -0
  79. package/src/hooks/use-open-editor-panel.ts +4 -3
  80. package/src/hooks/use-prop-value-history.ts +45 -0
  81. package/src/hooks/use-style-prop-history.ts +75 -0
  82. package/src/hooks/use-styles-field.ts +51 -0
  83. package/src/index.ts +2 -3
  84. package/src/init.ts +5 -4
  85. package/src/panel.ts +1 -0
  86. package/src/{controls/control-actions/actions/popover-action.tsx → popover-action.tsx} +2 -2
  87. package/src/sync/enqueue-font.ts +7 -0
  88. package/src/sync/get-elementor-config.ts +7 -0
  89. package/src/sync/{should-use-v2-panel.ts → is-atomic-widget-selected.ts} +2 -3
  90. package/src/sync/types.ts +20 -21
  91. package/src/components/accordion-section.tsx +0 -25
  92. package/src/components/control-label.tsx +0 -10
  93. package/src/components/style-sections/background-section/background-color-control.tsx +0 -20
  94. package/src/components/style-sections/effects-section/box-shadow-repeater.tsx +0 -224
  95. package/src/components/style-sections/position-section/z-index-control.tsx +0 -20
  96. package/src/components/style-sections/size-section.tsx +0 -49
  97. package/src/components/style-sections/spacing-section/linked-dimensions-control.tsx +0 -155
  98. package/src/components/style-sections/typography-section/font-size-control.tsx +0 -20
  99. package/src/components/style-sections/typography-section/letter-spacing-control.tsx +0 -20
  100. package/src/components/style-sections/typography-section/text-alignment-control.tsx +0 -47
  101. package/src/components/style-sections/typography-section/text-color-control.tsx +0 -20
  102. package/src/components/style-sections/typography-section/transform-control.tsx +0 -25
  103. package/src/components/style-sections/typography-section/word-spacing-control.tsx +0 -20
  104. package/src/controls/components/control-toggle-button-group.tsx +0 -59
  105. package/src/controls/components/repeater.tsx +0 -197
  106. package/src/controls/components/text-field-inner-selection.tsx +0 -79
  107. package/src/controls/control-actions/control-actions.tsx +0 -43
  108. package/src/controls/control-context.tsx +0 -22
  109. package/src/controls/control-replacement.ts +0 -34
  110. package/src/controls/control-types/color-control.tsx +0 -27
  111. package/src/controls/control-types/image-control.tsx +0 -66
  112. package/src/controls/control-types/image-media-control.tsx +0 -73
  113. package/src/controls/control-types/number-control.tsx +0 -29
  114. package/src/controls/control-types/select-control.tsx +0 -30
  115. package/src/controls/control-types/size-control.tsx +0 -71
  116. package/src/controls/control-types/text-area-control.tsx +0 -31
  117. package/src/controls/control-types/text-control.tsx +0 -17
  118. package/src/controls/control-types/toggle-control.tsx +0 -26
  119. package/src/controls/create-control-replacement.tsx +0 -53
  120. package/src/controls/create-control.tsx +0 -40
  121. package/src/controls/hooks/use-style-control.ts +0 -29
  122. package/src/controls/hooks/use-sync-external-state.tsx +0 -51
  123. package/src/controls/hooks/use-widget-settings.ts +0 -16
  124. package/src/controls/props/is-transformable.ts +0 -13
  125. package/src/controls/props/types.ts +0 -51
  126. package/src/controls/settings-control.tsx +0 -37
  127. package/src/controls/style-control.tsx +0 -20
  128. package/src/controls/sync/get-container.ts +0 -8
  129. package/src/controls/sync/update-settings.ts +0 -14
  130. package/src/controls/types.ts +0 -39
  131. package/src/dynamics/hooks/use-prop-value-history.ts +0 -26
  132. package/src/hooks/use-element-style-prop.ts +0 -46
  133. package/src/hooks/use-element-styles.ts +0 -13
  134. package/src/hooks/use-element-type.ts +0 -33
  135. package/src/hooks/use-selected-elements.ts +0 -9
  136. package/src/sync/get-element-styles.ts +0 -9
  137. package/src/sync/get-selected-elements.ts +0 -21
  138. package/src/sync/get-widgets-cache.ts +0 -7
  139. package/src/sync/update-style.ts +0 -25
@@ -1,18 +1,20 @@
1
1
  import * as React from 'react';
2
- import { Stack } from '@elementor/ui';
3
- import { SettingsControl } from '../controls/settings-control';
4
- import { useElement } from '../controls/providers/element-provider';
5
- import { AccordionSection } from './accordion-section';
6
- import type { Control } from '../controls/types';
7
- import { Control as BaseControl } from '../controls/control';
8
- import { ControlType, getControlByType } from '../controls/controls-registry';
9
- import { ControlTypeContainer } from '../controls/components/control-type-container';
2
+ import { ControlLabel } from '@elementor/editor-controls';
3
+ import { type Control } from '@elementor/editor-elements';
4
+
5
+ import { useElement } from '../contexts/element-context';
6
+ import { Control as BaseControl } from '../controls-registry/control';
7
+ import { ControlTypeContainer } from '../controls-registry/control-type-container';
8
+ import { type ControlType, getControlByType } from '../controls-registry/controls-registry';
9
+ import { SettingsField } from '../controls-registry/settings-field';
10
+ import { Section } from './section';
11
+ import { SectionsList } from './sections-list';
10
12
 
11
13
  export const SettingsTab = () => {
12
14
  const { elementType } = useElement();
13
15
 
14
16
  return (
15
- <Stack>
17
+ <SectionsList>
16
18
  { elementType.controls.map( ( { type, value }, index ) => {
17
19
  if ( type === 'control' ) {
18
20
  return <Control key={ value.bind } control={ value } />;
@@ -20,7 +22,7 @@ export const SettingsTab = () => {
20
22
 
21
23
  if ( type === 'section' ) {
22
24
  return (
23
- <AccordionSection key={ type + '.' + index } title={ value.label }>
25
+ <Section title={ value.label } key={ type + '.' + index } defaultExpanded={ true }>
24
26
  { value.items?.map( ( item ) => {
25
27
  if ( item.type === 'control' ) {
26
28
  return <Control key={ item.value.bind } control={ item.value } />;
@@ -29,28 +31,27 @@ export const SettingsTab = () => {
29
31
  // TODO: Handle 2nd level sections
30
32
  return null;
31
33
  } ) }
32
- </AccordionSection>
34
+ </Section>
33
35
  );
34
36
  }
35
37
 
36
38
  return null;
37
39
  } ) }
38
- </Stack>
40
+ </SectionsList>
39
41
  );
40
42
  };
41
43
 
42
- // TODO: Create control wrapper by type for different layouts.
43
44
  const Control = ( { control }: { control: Control[ 'value' ] } ) => {
44
45
  if ( ! getControlByType( control.type as ControlType ) ) {
45
46
  return null;
46
47
  }
47
48
 
48
49
  return (
49
- <SettingsControl bind={ control.bind }>
50
+ <SettingsField bind={ control.bind }>
50
51
  <ControlTypeContainer controlType={ control.type as ControlType }>
51
- { control.label ? <SettingsControl.Label>{ control.label }</SettingsControl.Label> : null }
52
+ { control.label ? <ControlLabel>{ control.label }</ControlLabel> : null }
52
53
  <BaseControl type={ control.type as ControlType } props={ control.props } />
53
54
  </ControlTypeContainer>
54
- </SettingsControl>
55
+ </SettingsField>
55
56
  );
56
57
  };
@@ -0,0 +1,21 @@
1
+ import * as React from 'react';
2
+ import { ColorControl, ControlLabel } from '@elementor/editor-controls';
3
+ import { Grid } from '@elementor/ui';
4
+ import { __ } from '@wordpress/i18n';
5
+
6
+ import { StylesField } from '../../../controls-registry/styles-field';
7
+
8
+ export const BackgroundColorField = () => {
9
+ return (
10
+ <StylesField bind="background-color">
11
+ <Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
12
+ <Grid item xs={ 6 }>
13
+ <ControlLabel>{ __( 'Color', 'elementor' ) }</ControlLabel>
14
+ </Grid>
15
+ <Grid item xs={ 6 }>
16
+ <ColorControl />
17
+ </Grid>
18
+ </Grid>
19
+ </StylesField>
20
+ );
21
+ };
@@ -1,15 +1,17 @@
1
1
  import * as React from 'react';
2
- import { __ } from '@wordpress/i18n';
2
+ import { BackgroundOverlayRepeaterControl } from '@elementor/editor-controls';
3
3
  import { Stack } from '@elementor/ui';
4
- import { AccordionSection } from '../../accordion-section';
5
- import { BackgroundColorControl } from './background-color-control';
4
+
5
+ import { StylesField } from '../../../controls-registry/styles-field';
6
+ import { BackgroundColorField } from './background-color-field';
6
7
 
7
8
  export const BackgroundSection = () => {
8
9
  return (
9
- <AccordionSection title={ __( 'Background', 'elementor' ) }>
10
- <Stack gap={ 1.5 }>
11
- <BackgroundColorControl />
12
- </Stack>
13
- </AccordionSection>
10
+ <Stack gap={ 1.5 }>
11
+ <StylesField bind="background-image">
12
+ <BackgroundOverlayRepeaterControl />
13
+ </StylesField>
14
+ <BackgroundColorField />
15
+ </Stack>
14
16
  );
15
17
  };
@@ -0,0 +1,21 @@
1
+ import * as React from 'react';
2
+ import { ColorControl, ControlLabel } from '@elementor/editor-controls';
3
+ import { Grid } from '@elementor/ui';
4
+ import { __ } from '@wordpress/i18n';
5
+
6
+ import { StylesField } from '../../../controls-registry/styles-field';
7
+
8
+ export const BorderColorField = () => {
9
+ return (
10
+ <StylesField bind={ 'border-color' }>
11
+ <Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
12
+ <Grid item xs={ 6 }>
13
+ <ControlLabel>{ __( 'Border Color', 'elementor' ) }</ControlLabel>
14
+ </Grid>
15
+ <Grid item xs={ 6 }>
16
+ <ColorControl />
17
+ </Grid>
18
+ </Grid>
19
+ </StylesField>
20
+ );
21
+ };
@@ -0,0 +1,48 @@
1
+ import * as React from 'react';
2
+ import { __ } from '@wordpress/i18n';
3
+
4
+ import { useStylesField } from '../../../hooks/use-styles-field';
5
+ import { AddOrRemoveContent } from '../../add-or-remove-content';
6
+ import { BorderColorField } from './border-color-field';
7
+ import { BorderStyleField } from './border-style-field';
8
+ import { BorderWidthField } from './border-width-field';
9
+
10
+ const initialSize = { $$type: 'size', value: { size: 1, unit: 'px' } };
11
+ const initialBorderWidth = {
12
+ $$type: 'border-width',
13
+ value: { top: initialSize, right: initialSize, bottom: initialSize, left: initialSize },
14
+ };
15
+ const initialBorderColor = { $$type: 'color', value: '#000000' };
16
+ const initialBorderStyle = 'solid';
17
+
18
+ export const BorderField = () => {
19
+ const [ borderWidth, setBorderWidth ] = useStylesField( 'border-width' );
20
+ const [ borderColor, setBorderColor ] = useStylesField( 'border-color' );
21
+ const [ borderStyle, setBorderStyle ] = useStylesField( 'border-style' );
22
+
23
+ const addBorder = () => {
24
+ setBorderWidth( initialBorderWidth );
25
+ setBorderColor( initialBorderColor );
26
+ setBorderStyle( initialBorderStyle );
27
+ };
28
+ const removeBorder = () => {
29
+ setBorderWidth( null );
30
+ setBorderColor( null );
31
+ setBorderStyle( null );
32
+ };
33
+
34
+ const hasBorder = Boolean( borderWidth || borderColor || borderStyle );
35
+
36
+ return (
37
+ <AddOrRemoveContent
38
+ label={ __( 'Border', 'elementor' ) }
39
+ isAdded={ hasBorder }
40
+ onAdd={ addBorder }
41
+ onRemove={ removeBorder }
42
+ >
43
+ <BorderWidthField />
44
+ <BorderColorField />
45
+ <BorderStyleField />
46
+ </AddOrRemoveContent>
47
+ );
48
+ };
@@ -0,0 +1,49 @@
1
+ import * as React from 'react';
2
+ import { type EqualUnequalItems, EqualUnequalSizesControl } from '@elementor/editor-controls';
3
+ import type { BorderRadiusPropValue } from '@elementor/editor-props';
4
+ import {
5
+ BorderCornersIcon,
6
+ RadiusBottomLeftIcon,
7
+ RadiusBottomRightIcon,
8
+ RadiusTopLeftIcon,
9
+ RadiusTopRightIcon,
10
+ } from '@elementor/icons';
11
+ import { __ } from '@wordpress/i18n';
12
+
13
+ import { StylesField } from '../../../controls-registry/styles-field';
14
+
15
+ const corners: EqualUnequalItems< BorderRadiusPropValue[ '$$type' ], BorderRadiusPropValue > = [
16
+ {
17
+ label: __( 'Top Left', 'elementor' ),
18
+ icon: <RadiusTopLeftIcon fontSize={ 'tiny' } />,
19
+ bind: 'top-left',
20
+ },
21
+ {
22
+ label: __( 'Top Right', 'elementor' ),
23
+ icon: <RadiusTopRightIcon fontSize={ 'tiny' } />,
24
+ bind: 'top-right',
25
+ },
26
+ {
27
+ label: __( 'Bottom Right', 'elementor' ),
28
+ icon: <RadiusBottomRightIcon fontSize={ 'tiny' } />,
29
+ bind: 'bottom-right',
30
+ },
31
+ {
32
+ label: __( 'Bottom Left', 'elementor' ),
33
+ icon: <RadiusBottomLeftIcon fontSize={ 'tiny' } />,
34
+ bind: 'bottom-left',
35
+ },
36
+ ];
37
+
38
+ export const BorderRadiusField = () => {
39
+ return (
40
+ <StylesField bind={ 'border-radius' }>
41
+ <EqualUnequalSizesControl
42
+ label={ __( 'Border Radius', 'elementor' ) }
43
+ icon={ <BorderCornersIcon fontSize={ 'tiny' } /> }
44
+ items={ corners }
45
+ multiSizeType={ 'border-radius' }
46
+ />
47
+ </StylesField>
48
+ );
49
+ };
@@ -0,0 +1,13 @@
1
+ import * as React from 'react';
2
+ import { Divider, Stack } from '@elementor/ui';
3
+
4
+ import { BorderField } from './border-field';
5
+ import { BorderRadiusField } from './border-radius-field';
6
+
7
+ export const BorderSection = () => (
8
+ <Stack gap={ 1.5 }>
9
+ <BorderRadiusField />
10
+ <Divider />
11
+ <BorderField />
12
+ </Stack>
13
+ );
@@ -0,0 +1,32 @@
1
+ import * as React from 'react';
2
+ import { ControlLabel, SelectControl } from '@elementor/editor-controls';
3
+ import { Grid } from '@elementor/ui';
4
+ import { __ } from '@wordpress/i18n';
5
+
6
+ import { StylesField } from '../../../controls-registry/styles-field';
7
+
8
+ const borderStyles = [
9
+ { value: 'none', label: __( 'None', 'elementor' ) },
10
+ { value: 'solid', label: __( 'Solid', 'elementor' ) },
11
+ { value: 'dashed', label: __( 'Dashed', 'elementor' ) },
12
+ { value: 'dotted', label: __( 'Dotted', 'elementor' ) },
13
+ { value: 'double', label: __( 'Double', 'elementor' ) },
14
+ { value: 'groove', label: __( 'Groove', 'elementor' ) },
15
+ { value: 'ridge', label: __( 'Ridge', 'elementor' ) },
16
+ { value: 'inset', label: __( 'Inset', 'elementor' ) },
17
+ { value: 'outset', label: __( 'Outset', 'elementor' ) },
18
+ ];
19
+ export const BorderStyleField = () => {
20
+ return (
21
+ <StylesField bind={ 'border-style' }>
22
+ <Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
23
+ <Grid item xs={ 6 }>
24
+ <ControlLabel>{ __( 'Border Type', 'elementor' ) }</ControlLabel>
25
+ </Grid>
26
+ <Grid item xs={ 6 }>
27
+ <SelectControl options={ borderStyles } />
28
+ </Grid>
29
+ </Grid>
30
+ </StylesField>
31
+ );
32
+ };
@@ -0,0 +1,43 @@
1
+ import * as React from 'react';
2
+ import { type EqualUnequalItems, EqualUnequalSizesControl } from '@elementor/editor-controls';
3
+ import { type BorderWidthPropValue } from '@elementor/editor-props';
4
+ import { SideAllIcon, SideBottomIcon, SideLeftIcon, SideRightIcon, SideTopIcon } from '@elementor/icons';
5
+ import { __ } from '@wordpress/i18n';
6
+
7
+ import { StylesField } from '../../../controls-registry/styles-field';
8
+
9
+ const edges: EqualUnequalItems< BorderWidthPropValue[ '$$type' ], BorderWidthPropValue > = [
10
+ {
11
+ label: __( 'Top', 'elementor' ),
12
+ icon: <SideTopIcon fontSize={ 'tiny' } />,
13
+ bind: 'top',
14
+ },
15
+ {
16
+ label: __( 'Right', 'elementor' ),
17
+ icon: <SideRightIcon fontSize={ 'tiny' } />,
18
+ bind: 'right',
19
+ },
20
+ {
21
+ label: __( 'Bottom', 'elementor' ),
22
+ icon: <SideBottomIcon fontSize={ 'tiny' } />,
23
+ bind: 'bottom',
24
+ },
25
+ {
26
+ label: __( 'Left', 'elementor' ),
27
+ icon: <SideLeftIcon fontSize={ 'tiny' } />,
28
+ bind: 'left',
29
+ },
30
+ ];
31
+
32
+ export const BorderWidthField = () => {
33
+ return (
34
+ <StylesField bind={ 'border-width' }>
35
+ <EqualUnequalSizesControl
36
+ label={ __( 'Border Width', 'elementor' ) }
37
+ icon={ <SideAllIcon fontSize={ 'tiny' } /> }
38
+ items={ edges }
39
+ multiSizeType={ 'border-width' }
40
+ />
41
+ </StylesField>
42
+ );
43
+ };
@@ -1,18 +1,15 @@
1
1
  import * as React from 'react';
2
- import { __ } from '@wordpress/i18n';
2
+ import { BoxShadowRepeaterControl } from '@elementor/editor-controls';
3
3
  import { Stack } from '@elementor/ui';
4
- import { AccordionSection } from '../../accordion-section';
5
- import { StyleControl } from '../../../controls/style-control';
6
- import { BoxShadowRepeater } from './box-shadow-repeater';
4
+
5
+ import { StylesField } from '../../../controls-registry/styles-field';
7
6
 
8
7
  export const EffectsSection = () => {
9
8
  return (
10
- <AccordionSection title={ __( 'Effects', 'elementor' ) }>
11
- <Stack gap={ 1.5 }>
12
- <StyleControl bind="box-shadow">
13
- <BoxShadowRepeater />
14
- </StyleControl>
15
- </Stack>
16
- </AccordionSection>
9
+ <Stack gap={ 1.5 }>
10
+ <StylesField bind="box-shadow">
11
+ <BoxShadowRepeaterControl />
12
+ </StylesField>
13
+ </Stack>
17
14
  );
18
15
  };
@@ -0,0 +1,32 @@
1
+ import * as React from 'react';
2
+ import { ControlLabel, type ToggleButtonGroupItem, ToggleControl } from '@elementor/editor-controls';
3
+ import { Stack } from '@elementor/ui';
4
+ import { __ } from '@wordpress/i18n';
5
+
6
+ import { StylesField } from '../../../controls-registry/styles-field';
7
+
8
+ type Displays = 'block' | 'flex';
9
+
10
+ export const DisplayField = () => {
11
+ const options: ToggleButtonGroupItem< Displays >[] = [
12
+ {
13
+ value: 'block',
14
+ renderContent: () => __( 'Block', 'elementor' ),
15
+ label: __( 'Block', 'elementor' ),
16
+ },
17
+ {
18
+ value: 'flex',
19
+ renderContent: () => __( 'Flex', 'elementor' ),
20
+ label: __( 'Flex', 'elementor' ),
21
+ },
22
+ ];
23
+
24
+ return (
25
+ <StylesField bind="display">
26
+ <Stack gap={ 1 }>
27
+ <ControlLabel>{ __( 'Display', 'elementor' ) }</ControlLabel>
28
+ <ToggleControl options={ options } fullWidth={ true } />
29
+ </Stack>
30
+ </StylesField>
31
+ );
32
+ };
@@ -0,0 +1,82 @@
1
+ import * as React from 'react';
2
+ import { ControlLabel, type ToggleButtonGroupItem, ToggleControl } from '@elementor/editor-controls';
3
+ import {
4
+ JustifyBottomIcon,
5
+ JustifyCenterIcon,
6
+ JustifyDistributeVerticalIcon,
7
+ JustifySpaceAroundVerticalIcon,
8
+ JustifySpaceBetweenVerticalIcon,
9
+ JustifyTopIcon,
10
+ } from '@elementor/icons';
11
+ import { Stack } from '@elementor/ui';
12
+ import { __ } from '@wordpress/i18n';
13
+
14
+ import { StylesField } from '../../../controls-registry/styles-field';
15
+ import { useDirection } from '../../../hooks/use-direction';
16
+ import { useStylesField } from '../../../hooks/use-styles-field';
17
+ import { rotateFlexIcon } from './utils/rotate-flex-icon';
18
+
19
+ type JustifyContent = 'start' | 'center' | 'end' | 'space-between' | 'space-around' | 'space-evenly';
20
+
21
+ export const JustifyContentField = () => {
22
+ const [ direction ] = useStylesField( 'flex-direction' );
23
+
24
+ const { isUiRtl, isSiteRtl } = useDirection(),
25
+ sx = { transform: rotateFlexIcon( direction as string, -1 ) } as const,
26
+ shouldReverseOrder = isSiteRtl !== isUiRtl;
27
+
28
+ const StartIcon = isSiteRtl ? JustifyBottomIcon : JustifyTopIcon,
29
+ EndIcon = isSiteRtl ? JustifyTopIcon : JustifyBottomIcon;
30
+
31
+ const options: ToggleButtonGroupItem< JustifyContent >[] = [
32
+ {
33
+ value: 'start',
34
+ label: __( 'Start', 'elementor' ),
35
+ renderContent: ( { size } ) => <StartIcon fontSize={ size } sx={ sx } />,
36
+ showTooltip: true,
37
+ },
38
+ {
39
+ value: 'center',
40
+ label: __( 'Center', 'elementor' ),
41
+ renderContent: ( { size } ) => <JustifyCenterIcon fontSize={ size } sx={ sx } />,
42
+ showTooltip: true,
43
+ },
44
+ {
45
+ value: 'end',
46
+ label: __( 'End', 'elementor' ),
47
+ renderContent: ( { size } ) => <EndIcon fontSize={ size } sx={ sx } />,
48
+ showTooltip: true,
49
+ },
50
+ {
51
+ value: 'space-between',
52
+ label: __( 'Space Between', 'elementor' ),
53
+ renderContent: ( { size } ) => <JustifySpaceBetweenVerticalIcon fontSize={ size } sx={ sx } />,
54
+ showTooltip: true,
55
+ },
56
+ {
57
+ value: 'space-around',
58
+ label: __( 'Space Around', 'elementor' ),
59
+ renderContent: ( { size } ) => <JustifySpaceAroundVerticalIcon fontSize={ size } sx={ sx } />,
60
+ showTooltip: true,
61
+ },
62
+ {
63
+ value: 'space-evenly',
64
+ label: __( 'Space Evenly', 'elementor' ),
65
+ renderContent: ( { size } ) => <JustifyDistributeVerticalIcon fontSize={ size } sx={ sx } />,
66
+ showTooltip: true,
67
+ },
68
+ ];
69
+
70
+ if ( shouldReverseOrder ) {
71
+ options.reverse();
72
+ }
73
+
74
+ 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>
81
+ );
82
+ };
@@ -0,0 +1,17 @@
1
+ import * as React from 'react';
2
+ import { Stack } from '@elementor/ui';
3
+
4
+ import { useStylesField } from '../../../hooks/use-styles-field';
5
+ import { DisplayField } from './display-field';
6
+ import { JustifyContentField } from './justify-content-field';
7
+
8
+ export const LayoutSection = () => {
9
+ const [ display ] = useStylesField( 'display' );
10
+
11
+ return (
12
+ <Stack gap={ 2 }>
13
+ <DisplayField />
14
+ { 'flex' === display && <JustifyContentField /> }
15
+ </Stack>
16
+ );
17
+ };
@@ -0,0 +1,12 @@
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
+ }
@@ -0,0 +1,46 @@
1
+ import * as React from 'react';
2
+ import { ControlLabel, SizeControl } from '@elementor/editor-controls';
3
+ import { SideBottomIcon, SideLeftIcon, SideRightIcon, SideTopIcon } from '@elementor/icons';
4
+ import { Grid, Stack } from '@elementor/ui';
5
+ import { __ } from '@wordpress/i18n';
6
+
7
+ import { StylesField } from '../../../controls-registry/styles-field';
8
+
9
+ export type Side = 'left' | 'right' | 'top' | 'bottom';
10
+
11
+ const sideIcons = {
12
+ left: <SideLeftIcon fontSize={ 'tiny' } />,
13
+ right: <SideRightIcon fontSize={ 'tiny' } />,
14
+ top: <SideTopIcon fontSize={ 'tiny' } />,
15
+ bottom: <SideBottomIcon fontSize={ 'tiny' } />,
16
+ };
17
+
18
+ export const DimensionsField = () => {
19
+ return (
20
+ <>
21
+ <Stack direction="row" gap={ 2 } flexWrap="nowrap">
22
+ <DimensionField side="top" label={ __( 'Top', 'elementor' ) } />
23
+ <DimensionField side="right" label={ __( 'Right', 'elementor' ) } />
24
+ </Stack>
25
+ <Stack direction="row" gap={ 2 } flexWrap="nowrap">
26
+ <DimensionField side="bottom" label={ __( 'Bottom', 'elementor' ) } />
27
+ <DimensionField side="left" label={ __( 'Left', 'elementor' ) } />
28
+ </Stack>
29
+ </>
30
+ );
31
+ };
32
+
33
+ const DimensionField = ( { side, label }: { side: Side; label: string } ) => {
34
+ return (
35
+ <Grid container gap={ 1 } alignItems="center">
36
+ <Grid item xs={ 12 }>
37
+ <ControlLabel>{ label }</ControlLabel>
38
+ </Grid>
39
+ <Grid item xs={ 12 }>
40
+ <StylesField bind={ side }>
41
+ <SizeControl startIcon={ sideIcons[ side ] } />
42
+ </StylesField>
43
+ </Grid>
44
+ </Grid>
45
+ );
46
+ };
@@ -0,0 +1,28 @@
1
+ import * as React from 'react';
2
+ import { ControlLabel, SelectControl } from '@elementor/editor-controls';
3
+ import { Grid } from '@elementor/ui';
4
+ import { __ } from '@wordpress/i18n';
5
+
6
+ import { StylesField } from '../../../controls-registry/styles-field';
7
+
8
+ const positionOptions = [
9
+ { label: __( 'Static', 'elementor' ), value: 'static' },
10
+ { label: __( 'Relative', 'elementor' ), value: 'relative' },
11
+ { label: __( 'Absolute', 'elementor' ), value: 'absolute' },
12
+ { label: __( 'Fixed', 'elementor' ), value: 'fixed' },
13
+ ];
14
+
15
+ export const PositionField = () => {
16
+ return (
17
+ <StylesField bind="position">
18
+ <Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
19
+ <Grid item xs={ 6 }>
20
+ <ControlLabel>{ __( 'Position', 'elementor' ) }</ControlLabel>
21
+ </Grid>
22
+ <Grid item xs={ 6 }>
23
+ <SelectControl options={ positionOptions } />
24
+ </Grid>
25
+ </Grid>
26
+ </StylesField>
27
+ );
28
+ };
@@ -1,15 +1,58 @@
1
1
  import * as React from 'react';
2
- import { AccordionSection } from '../../accordion-section';
2
+ import { useCallback } from 'react';
3
+ import type { PropValue } from '@elementor/editor-props';
3
4
  import { Stack } from '@elementor/ui';
4
- import { ZIndexControl } from './z-index-control';
5
- import { __ } from '@wordpress/i18n';
5
+
6
+ import { useStylePropsHistory } from '../../../hooks/use-style-prop-history';
7
+ import { useStylesField } from '../../../hooks/use-styles-field';
8
+ import { DimensionsField } from './dimensions-field';
9
+ import { PositionField } from './position-field';
10
+ import { ZIndexField } from './z-index-field';
11
+
12
+ const dimensionsPropKeys = [ 'top', 'bottom', 'left', 'right' ];
6
13
 
7
14
  export const PositionSection = () => {
15
+ const [ positionValue ] = useStylesField( 'position' );
16
+ usePositionChangeHandler();
17
+
18
+ const isNotStatic = positionValue && positionValue !== 'static';
19
+
8
20
  return (
9
- <AccordionSection title={ __( 'Position', 'elementor' ) }>
10
- <Stack gap={ 1.5 }>
11
- <ZIndexControl />
12
- </Stack>
13
- </AccordionSection>
21
+ <Stack gap={ 1.5 }>
22
+ <PositionField />
23
+ { isNotStatic ? (
24
+ <>
25
+ <DimensionsField />
26
+ <ZIndexField />
27
+ </>
28
+ ) : null }
29
+ </Stack>
30
+ );
31
+ };
32
+
33
+ const usePositionChangeHandler = () => {
34
+ const dimensionsHistory = useStylePropsHistory( dimensionsPropKeys );
35
+
36
+ const onPositionChange = useCallback(
37
+ ( newPositionValue: PropValue, previousPosition: PropValue ) => {
38
+ if ( ! dimensionsHistory ) {
39
+ return;
40
+ }
41
+
42
+ const { saveStylePropsHistory, updateStylePropsFromHistory, clearCurrentStyleProps } = dimensionsHistory;
43
+
44
+ if ( newPositionValue === 'static' ) {
45
+ saveStylePropsHistory();
46
+ clearCurrentStyleProps();
47
+ } else if ( previousPosition === 'static' ) {
48
+ updateStylePropsFromHistory();
49
+ }
50
+
51
+ previousPosition = newPositionValue;
52
+ },
53
+ [ dimensionsHistory ]
14
54
  );
55
+
56
+ const [ , , registerChangeListener ] = useStylesField< PropValue >( 'position' );
57
+ registerChangeListener?.( onPositionChange );
15
58
  };