@elementor/editor-controls 0.12.1 → 0.14.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@elementor/editor-controls",
3
3
  "description": "This package contains the controls model and utils for the Elementor editor",
4
- "version": "0.12.1",
4
+ "version": "0.14.0",
5
5
  "private": false,
6
6
  "author": "Elementor Team",
7
7
  "homepage": "https://elementor.com/",
@@ -40,14 +40,14 @@
40
40
  "dev": "tsup --config=../../tsup.dev.ts"
41
41
  },
42
42
  "dependencies": {
43
- "@elementor/editor-props": "0.9.2",
43
+ "@elementor/editor-props": "0.9.3",
44
44
  "@elementor/env": "0.3.5",
45
45
  "@elementor/http": "0.1.3",
46
46
  "@elementor/icons": "1.31.0",
47
47
  "@elementor/session": "0.1.0",
48
48
  "@elementor/ui": "1.26.0",
49
- "@elementor/utils": "0.3.1",
50
- "@elementor/wp-media": "0.4.1",
49
+ "@elementor/utils": "0.4.0",
50
+ "@elementor/wp-media": "0.4.2",
51
51
  "@wordpress/i18n": "^5.13.0"
52
52
  },
53
53
  "devDependencies": {
@@ -16,7 +16,9 @@ import {
16
16
  } from '@elementor/ui';
17
17
  import { __ } from '@wordpress/i18n';
18
18
 
19
+ import { useSyncExternalState } from '../hooks/use-sync-external-state';
19
20
  import { SectionContent } from './section-content';
21
+ import { SortableItem, SortableProvider } from './sortable';
20
22
 
21
23
  const SIZE = 'tiny';
22
24
 
@@ -50,32 +52,61 @@ export const Repeater = < T, >( {
50
52
  values: repeaterValues = [],
51
53
  setValues: setRepeaterValues,
52
54
  }: RepeaterProps< Item< T > > ) => {
55
+ const [ items, setItems ] = useSyncExternalState( {
56
+ external: repeaterValues,
57
+ // @ts-expect-error - as long as persistWhen => true, value will never be null
58
+ setExternal: setRepeaterValues,
59
+ persistWhen: () => true,
60
+ } );
61
+
62
+ const [ uniqueKeys, setUniqueKeys ] = useState( items.map( ( _, index ) => index ) );
63
+
64
+ const generateNextKey = ( source: number[] ) => {
65
+ return 1 + Math.max( 0, ...source );
66
+ };
67
+
53
68
  const addRepeaterItem = () => {
54
69
  const newItem = structuredClone( itemSettings.initialValues );
70
+ const newKey = generateNextKey( uniqueKeys );
55
71
 
56
72
  if ( addToBottom ) {
57
- return setRepeaterValues( [ ...repeaterValues, newItem ] );
73
+ setItems( [ ...items, newItem ] );
74
+ setUniqueKeys( [ ...uniqueKeys, newKey ] );
75
+ } else {
76
+ setItems( [ newItem, ...items ] );
77
+ setUniqueKeys( [ newKey, ...uniqueKeys ] );
58
78
  }
59
-
60
- setRepeaterValues( [ newItem, ...repeaterValues ] );
61
79
  };
62
80
 
63
81
  const duplicateRepeaterItem = ( index: number ) => {
64
- setRepeaterValues( [
65
- ...repeaterValues.slice( 0, index ),
66
- structuredClone( repeaterValues[ index ] ),
67
- ...repeaterValues.slice( index ),
68
- ] );
82
+ const newItem = structuredClone( items[ index ] );
83
+ const newKey = generateNextKey( uniqueKeys );
84
+
85
+ // Insert the new (cloned item) at the next spot (after the current index)
86
+ const atPosition = 1 + index;
87
+
88
+ setItems( [ ...items.slice( 0, atPosition ), newItem, ...items.slice( atPosition ) ] );
89
+ setUniqueKeys( [ ...uniqueKeys.slice( 0, atPosition ), newKey, ...uniqueKeys.slice( atPosition ) ] );
69
90
  };
70
91
 
71
92
  const removeRepeaterItem = ( index: number ) => {
72
- setRepeaterValues( repeaterValues.filter( ( _, i ) => i !== index ) );
93
+ setUniqueKeys(
94
+ uniqueKeys.filter( ( _, pos ) => {
95
+ return pos !== index;
96
+ } )
97
+ );
98
+
99
+ setItems(
100
+ items.filter( ( _, pos ) => {
101
+ return pos !== index;
102
+ } )
103
+ );
73
104
  };
74
105
 
75
106
  const toggleDisableRepeaterItem = ( index: number ) => {
76
- setRepeaterValues(
77
- repeaterValues.map( ( value, i ) => {
78
- if ( i === index ) {
107
+ setItems(
108
+ items.map( ( value, pos ) => {
109
+ if ( pos === index ) {
79
110
  const { disabled, ...rest } = value;
80
111
 
81
112
  // If the items should not be disabled, remove the disabled property.
@@ -87,6 +118,16 @@ export const Repeater = < T, >( {
87
118
  );
88
119
  };
89
120
 
121
+ const onChangeOrder = ( reorderedKeys: number[] ) => {
122
+ setUniqueKeys( reorderedKeys );
123
+ setItems( ( prevItems ) => {
124
+ return reorderedKeys.map( ( keyValue ) => {
125
+ const index = uniqueKeys.indexOf( keyValue );
126
+ return prevItems[ index ];
127
+ } );
128
+ } );
129
+ };
130
+
90
131
  return (
91
132
  <SectionContent>
92
133
  <Stack direction="row" justifyContent="space-between" alignItems="center">
@@ -97,22 +138,35 @@ export const Repeater = < T, >( {
97
138
  <PlusIcon fontSize={ SIZE } />
98
139
  </IconButton>
99
140
  </Stack>
100
- <Stack gap={ 1 } sx={ { '&:empty': { display: 'none' } } }>
101
- { repeaterValues.map( ( value, index ) => (
102
- <RepeaterItem
103
- key={ index }
104
- bind={ String( index ) }
105
- disabled={ value.disabled }
106
- label={ <itemSettings.Label value={ value } /> }
107
- startIcon={ <itemSettings.Icon value={ value } /> }
108
- removeItem={ () => removeRepeaterItem( index ) }
109
- duplicateItem={ () => duplicateRepeaterItem( index ) }
110
- toggleDisableItem={ () => toggleDisableRepeaterItem( index ) }
111
- >
112
- { ( props ) => <itemSettings.Content { ...props } value={ value } bind={ String( index ) } /> }
113
- </RepeaterItem>
114
- ) ) }
115
- </Stack>
141
+ { 0 < uniqueKeys.length && (
142
+ <SortableProvider value={ uniqueKeys } onChange={ onChangeOrder }>
143
+ { uniqueKeys.map( ( key, index ) => {
144
+ const value = items[ index ];
145
+
146
+ if ( ! value ) {
147
+ return null;
148
+ }
149
+
150
+ return (
151
+ <SortableItem id={ key } key={ `sortable-${ key }` }>
152
+ <RepeaterItem
153
+ bind={ String( index ) }
154
+ disabled={ value?.disabled }
155
+ label={ <itemSettings.Label value={ value } /> }
156
+ startIcon={ <itemSettings.Icon value={ value } /> }
157
+ removeItem={ () => removeRepeaterItem( index ) }
158
+ duplicateItem={ () => duplicateRepeaterItem( index ) }
159
+ toggleDisableItem={ () => toggleDisableRepeaterItem( index ) }
160
+ >
161
+ { ( props ) => (
162
+ <itemSettings.Content { ...props } value={ value } bind={ String( index ) } />
163
+ ) }
164
+ </RepeaterItem>
165
+ </SortableItem>
166
+ );
167
+ } ) }
168
+ </SortableProvider>
169
+ ) }
116
170
  </SectionContent>
117
171
  );
118
172
  };
@@ -151,6 +205,7 @@ const RepeaterItem = ( {
151
205
  <UnstableTag
152
206
  label={ label }
153
207
  showActionsOnHover
208
+ fullWidth
154
209
  ref={ controlRef }
155
210
  variant="outlined"
156
211
  aria-label={ __( 'Open item', 'elementor' ) }
@@ -183,6 +238,7 @@ const RepeaterItem = ( {
183
238
  </IconButton>
184
239
  </>
185
240
  }
241
+ sx={ { backgroundColor: 'background.paper' } }
186
242
  />
187
243
  <Popover
188
244
  disablePortal
@@ -0,0 +1,108 @@
1
+ import * as React from 'react';
2
+ import { GripVerticalIcon } from '@elementor/icons';
3
+ import {
4
+ Divider,
5
+ List,
6
+ ListItem,
7
+ styled,
8
+ UnstableSortableItem,
9
+ type UnstableSortableItemProps,
10
+ type UnstableSortableItemRenderProps,
11
+ UnstableSortableProvider,
12
+ type UnstableSortableProviderProps,
13
+ } from '@elementor/ui';
14
+
15
+ export const SortableProvider = < T extends number >( props: UnstableSortableProviderProps< T > ) => {
16
+ return (
17
+ <List sx={ { p: 0, m: 0 } }>
18
+ <UnstableSortableProvider
19
+ restrictAxis={ true }
20
+ disableDragOverlay={ false }
21
+ variant={ 'static' }
22
+ { ...props }
23
+ />
24
+ </List>
25
+ );
26
+ };
27
+
28
+ type SortableItemProps = {
29
+ id: UnstableSortableItemProps[ 'id' ];
30
+ children: React.ReactNode;
31
+ };
32
+
33
+ export const SortableItem = ( { id, children }: SortableItemProps ): React.ReactNode => {
34
+ return (
35
+ <UnstableSortableItem
36
+ id={ id }
37
+ render={ ( {
38
+ itemProps,
39
+ triggerProps,
40
+ itemStyle,
41
+ triggerStyle,
42
+ isDragOverlay,
43
+ showDropIndication,
44
+ dropIndicationStyle,
45
+ }: UnstableSortableItemRenderProps ) => {
46
+ return (
47
+ <StyledListItem
48
+ { ...itemProps }
49
+ style={ itemStyle }
50
+ sx={ { backgroundColor: isDragOverlay ? 'background.paper' : undefined } }
51
+ >
52
+ <SortableTrigger { ...triggerProps } style={ triggerStyle } />
53
+ { children }
54
+ { showDropIndication && <StyledDivider style={ dropIndicationStyle } /> }
55
+ </StyledListItem>
56
+ );
57
+ } }
58
+ />
59
+ );
60
+ };
61
+
62
+ const StyledListItem = styled( ListItem )`
63
+ position: relative;
64
+ margin-inline: 0px;
65
+ padding-inline: 0px;
66
+ padding-block: ${ ( { theme } ) => theme.spacing( 0.5 ) };
67
+
68
+ & .class-item-sortable-trigger {
69
+ color: ${ ( { theme } ) => theme.palette.action.active };
70
+ height: 100%;
71
+ display: flex;
72
+ align-items: center;
73
+ visibility: hidden;
74
+ position: absolute;
75
+ top: 50%;
76
+ padding-inline-end: ${ ( { theme } ) => theme.spacing( 0.5 ) };
77
+ transform: translate( -75%, -50% );
78
+ }
79
+
80
+ &:hover {
81
+ & .class-item-sortable-trigger {
82
+ visibility: visible;
83
+ }
84
+ }
85
+ `;
86
+
87
+ const SortableTrigger = ( props: React.HTMLAttributes< HTMLDivElement > ) => (
88
+ <div { ...props } role="button" className="class-item-sortable-trigger">
89
+ <GripVerticalIcon fontSize="tiny" />
90
+ </div>
91
+ );
92
+
93
+ const StyledDivider = styled( Divider )`
94
+ height: 0px;
95
+ border: none;
96
+ overflow: visible;
97
+
98
+ &:after {
99
+ --height: 2px;
100
+ content: '';
101
+ display: block;
102
+ width: 100%;
103
+ height: var( --height );
104
+ margin-block: calc( -1 * var( --height ) / 2 );
105
+ border-radius: ${ ( { theme } ) => theme.spacing( 0.5 ) };
106
+ background-color: ${ ( { theme } ) => theme.palette.text.primary };
107
+ }
108
+ `;
@@ -31,7 +31,7 @@ const repeatControlOptions: ToggleButtonGroupItem< Repeaters >[] = [
31
31
  },
32
32
  {
33
33
  value: 'no-repeat',
34
- label: __( 'No-Repeat', 'elementor' ),
34
+ label: __( 'No-repeat', 'elementor' ),
35
35
  renderContent: ( { size } ) => <XIcon fontSize={ size } />,
36
36
  showTooltip: true,
37
37
  },
@@ -88,12 +88,18 @@ export const BackgroundImageOverlaySize = () => {
88
88
  <PopoverGridContainer>
89
89
  <Grid item xs={ 6 }>
90
90
  <PropKeyProvider bind={ 'width' }>
91
- <SizeControl startIcon={ <ArrowsMoveHorizontalIcon fontSize={ 'tiny' } /> } />
91
+ <SizeControl
92
+ startIcon={ <ArrowsMoveHorizontalIcon fontSize={ 'tiny' } /> }
93
+ extendedValues={ [ 'auto' ] }
94
+ />
92
95
  </PropKeyProvider>
93
96
  </Grid>
94
97
  <Grid item xs={ 6 }>
95
98
  <PropKeyProvider bind={ 'height' }>
96
- <SizeControl startIcon={ <ArrowsMoveVerticalIcon fontSize={ 'tiny' } /> } />
99
+ <SizeControl
100
+ startIcon={ <ArrowsMoveVerticalIcon fontSize={ 'tiny' } /> }
101
+ extendedValues={ [ 'auto' ] }
102
+ />
97
103
  </PropKeyProvider>
98
104
  </Grid>
99
105
  </PopoverGridContainer>
@@ -71,7 +71,7 @@ export const FontFamilyControl = createControl( ( { fontFamilies } ) => {
71
71
  <Stack>
72
72
  <Stack direction="row" alignItems="center" pl={ 1.5 } pr={ 0.5 } py={ 1.5 }>
73
73
  <EditIcon fontSize={ SIZE } sx={ { mr: 0.5 } } />
74
- <Typography variant="subtitle2">{ __( 'Font Family', 'elementor' ) }</Typography>
74
+ <Typography variant="subtitle2">{ __( 'Font family', 'elementor' ) }</Typography>
75
75
  <IconButton size={ SIZE } sx={ { ml: 'auto' } } onClick={ handleClose }>
76
76
  <XIcon fontSize={ SIZE } />
77
77
  </IconButton>
@@ -82,7 +82,7 @@ export const FontFamilyControl = createControl( ( { fontFamilies } ) => {
82
82
  fullWidth
83
83
  size={ SIZE }
84
84
  value={ searchValue }
85
- placeholder={ __( 'Search', 'elementor' ) }
85
+ placeholder={ __( 'Search fonts…', 'elementor' ) }
86
86
  onChange={ handleSearch }
87
87
  InputProps={ {
88
88
  startAdornment: (
@@ -21,7 +21,7 @@ export const GapControl = createControl( ( { label }: { label: string } ) => {
21
21
 
22
22
  const onLinkToggle = () => {
23
23
  if ( ! isLinked ) {
24
- setSizeValue( directionValue?.column.value );
24
+ setSizeValue( directionValue?.column?.value );
25
25
  return;
26
26
  }
27
27
 
@@ -22,7 +22,7 @@ export const ImageControl = createControl(
22
22
  <PropProvider { ...propContext }>
23
23
  <Stack gap={ 1.5 }>
24
24
  <PropKeyProvider bind={ 'src' }>
25
- <ControlLabel> { __( 'Choose image', 'elementor' ) } </ControlLabel>
25
+ <ControlLabel> { __( 'Image', 'elementor' ) } </ControlLabel>
26
26
  <ImageMediaControl />
27
27
  </PropKeyProvider>
28
28
  <PropKeyProvider bind={ 'size' }>
@@ -66,7 +66,7 @@ export const ImageMediaControl = createControl( ( props: ImageMediaControlProps
66
66
  startIcon={ <UploadIcon /> }
67
67
  onClick={ () => open( { mode: 'upload' } ) }
68
68
  >
69
- { __( 'Upload image', 'elementor' ) }
69
+ { __( 'Upload', 'elementor' ) }
70
70
  </Button>
71
71
  </Stack>
72
72
  </CardOverlay>
@@ -12,6 +12,7 @@ import { type HttpResponse, httpService } from '@elementor/http';
12
12
  import { MinusIcon, PlusIcon } from '@elementor/icons';
13
13
  import { useSessionStorage } from '@elementor/session';
14
14
  import { Collapse, Divider, Grid, IconButton, Stack, Switch } from '@elementor/ui';
15
+ import { debounce } from '@elementor/utils';
15
16
  import { __ } from '@wordpress/i18n';
16
17
 
17
18
  import { PropKeyProvider, PropProvider, useBoundProp } from '../bound-prop-context';
@@ -191,7 +192,7 @@ const SwitchControl = () => {
191
192
  return (
192
193
  <Grid container alignItems="center" flexWrap="nowrap" justifyContent="space-between">
193
194
  <Grid item>
194
- <ControlLabel>{ __( 'Open in new tab', 'elementor' ) }</ControlLabel>
195
+ <ControlLabel>{ __( 'Open in a new tab', 'elementor' ) }</ControlLabel>
195
196
  </Grid>
196
197
  <Grid item>
197
198
  <Switch checked={ value } onClick={ onClick } />
@@ -238,15 +239,3 @@ function generateFirstLoadedOption( unionValue: LinkPropValue[ 'value' ] | null
238
239
  ]
239
240
  : [];
240
241
  }
241
-
242
- function debounce< TArgs extends unknown[] >( fn: ( ...args: TArgs ) => unknown, timeout: number ) {
243
- let timer: ReturnType< typeof setTimeout >;
244
-
245
- return ( ...args: TArgs ) => {
246
- clearTimeout( timer );
247
-
248
- timer = setTimeout( () => {
249
- fn( ...args );
250
- }, timeout );
251
- };
252
- }
@@ -7,111 +7,131 @@ import { __ } from '@wordpress/i18n';
7
7
  import { PropKeyProvider, PropProvider, useBoundProp } from '../bound-prop-context';
8
8
  import { ControlLabel } from '../components/control-label';
9
9
  import { createControl } from '../create-control';
10
- import { SizeControl } from './size-control';
10
+ import { type ExtendedValue, SizeControl } from './size-control';
11
11
 
12
- export const LinkedDimensionsControl = createControl( ( { label }: { label: string } ) => {
13
- const { value: dimensionsValue, setValue: setDimensionsValue, propType } = useBoundProp( dimensionsPropTypeUtil );
14
- const { value: sizeValue, setValue: setSizeValue } = useBoundProp( sizePropTypeUtil );
12
+ export const LinkedDimensionsControl = createControl(
13
+ ( { label, extendedValues }: { label: string; extendedValues?: ExtendedValue[] } ) => {
14
+ const {
15
+ value: dimensionsValue,
16
+ setValue: setDimensionsValue,
17
+ propType,
18
+ } = useBoundProp( dimensionsPropTypeUtil );
19
+ const { value: sizeValue, setValue: setSizeValue } = useBoundProp( sizePropTypeUtil );
15
20
 
16
- const isLinked = ! dimensionsValue && ! sizeValue ? true : !! sizeValue;
21
+ const isLinked = ! dimensionsValue && ! sizeValue ? true : !! sizeValue;
17
22
 
18
- const onLinkToggle = () => {
19
- if ( ! isLinked ) {
20
- setSizeValue( dimensionsValue?.top?.value );
21
- return;
22
- }
23
+ const onLinkToggle = () => {
24
+ if ( ! isLinked ) {
25
+ setSizeValue( dimensionsValue?.top?.value );
26
+ return;
27
+ }
23
28
 
24
- const value = sizeValue ? sizePropTypeUtil.create( sizeValue ) : null;
29
+ const value = sizeValue ? sizePropTypeUtil.create( sizeValue ) : null;
25
30
 
26
- setDimensionsValue( {
27
- top: value,
28
- right: value,
29
- bottom: value,
30
- left: value,
31
- } );
32
- };
31
+ setDimensionsValue( {
32
+ top: value,
33
+ right: value,
34
+ bottom: value,
35
+ left: value,
36
+ } );
37
+ };
33
38
 
34
- const LinkedIcon = isLinked ? LinkIcon : DetachIcon;
39
+ const LinkedIcon = isLinked ? LinkIcon : DetachIcon;
35
40
 
36
- return (
37
- <PropProvider propType={ propType } value={ dimensionsValue } setValue={ setDimensionsValue }>
38
- <Stack direction="row" gap={ 2 } flexWrap="nowrap">
39
- <ControlLabel>{ label }</ControlLabel>
40
- <ToggleButton
41
- aria-label={ __( 'Link inputs', 'elementor' ) }
42
- size={ 'tiny' }
43
- value={ 'check' }
44
- selected={ isLinked }
45
- sx={ { marginLeft: 'auto' } }
46
- onChange={ onLinkToggle }
47
- >
48
- <LinkedIcon fontSize={ 'tiny' } />
49
- </ToggleButton>
50
- </Stack>
51
- <Stack direction="row" gap={ 2 } flexWrap="nowrap">
52
- <Grid container gap={ 1 } alignItems="center">
53
- <Grid item xs={ 12 }>
54
- <ControlLabel>{ __( 'Top', 'elementor' ) }</ControlLabel>
55
- </Grid>
56
- <Grid item xs={ 12 }>
57
- <Control
58
- bind={ 'top' }
59
- startIcon={ <SideTopIcon fontSize={ 'tiny' } /> }
60
- isLinked={ isLinked }
61
- />
62
- </Grid>
63
- </Grid>
64
- <Grid container gap={ 1 } alignItems="center">
65
- <Grid item xs={ 12 }>
66
- <ControlLabel>{ __( 'Right', 'elementor' ) }</ControlLabel>
67
- </Grid>
68
- <Grid item xs={ 12 }>
69
- <Control
70
- bind={ 'right' }
71
- startIcon={ <SideRightIcon fontSize={ 'tiny' } /> }
72
- isLinked={ isLinked }
73
- />
41
+ return (
42
+ <PropProvider propType={ propType } value={ dimensionsValue } setValue={ setDimensionsValue }>
43
+ <Stack direction="row" gap={ 2 } flexWrap="nowrap">
44
+ <ControlLabel>{ label }</ControlLabel>
45
+ <ToggleButton
46
+ aria-label={ __( 'Link Inputs', 'elementor' ) }
47
+ size={ 'tiny' }
48
+ value={ 'check' }
49
+ selected={ isLinked }
50
+ sx={ { marginLeft: 'auto' } }
51
+ onChange={ onLinkToggle }
52
+ >
53
+ <LinkedIcon fontSize={ 'tiny' } />
54
+ </ToggleButton>
55
+ </Stack>
56
+ <Stack direction="row" gap={ 2 } flexWrap="nowrap">
57
+ <Grid container gap={ 1 } alignItems="center">
58
+ <Grid item xs={ 12 }>
59
+ <ControlLabel>{ __( 'Top', 'elementor' ) }</ControlLabel>
60
+ </Grid>
61
+ <Grid item xs={ 12 }>
62
+ <Control
63
+ bind={ 'top' }
64
+ startIcon={ <SideTopIcon fontSize={ 'tiny' } /> }
65
+ isLinked={ isLinked }
66
+ extendedValues={ extendedValues }
67
+ />
68
+ </Grid>
74
69
  </Grid>
75
- </Grid>
76
- </Stack>
77
- <Stack direction="row" gap={ 2 } flexWrap="nowrap">
78
- <Grid container gap={ 1 } alignItems="center">
79
- <Grid item xs={ 12 }>
80
- <ControlLabel>{ __( 'Bottom', 'elementor' ) }</ControlLabel>
70
+ <Grid container gap={ 1 } alignItems="center">
71
+ <Grid item xs={ 12 }>
72
+ <ControlLabel>{ __( 'Right', 'elementor' ) }</ControlLabel>
73
+ </Grid>
74
+ <Grid item xs={ 12 }>
75
+ <Control
76
+ bind={ 'right' }
77
+ startIcon={ <SideRightIcon fontSize={ 'tiny' } /> }
78
+ isLinked={ isLinked }
79
+ extendedValues={ extendedValues }
80
+ />
81
+ </Grid>
81
82
  </Grid>
82
- <Grid item xs={ 12 }>
83
- <Control
84
- bind={ 'bottom' }
85
- startIcon={ <SideBottomIcon fontSize={ 'tiny' } /> }
86
- isLinked={ isLinked }
87
- />
83
+ </Stack>
84
+ <Stack direction="row" gap={ 2 } flexWrap="nowrap">
85
+ <Grid container gap={ 1 } alignItems="center">
86
+ <Grid item xs={ 12 }>
87
+ <ControlLabel>{ __( 'Bottom', 'elementor' ) }</ControlLabel>
88
+ </Grid>
89
+ <Grid item xs={ 12 }>
90
+ <Control
91
+ bind={ 'bottom' }
92
+ startIcon={ <SideBottomIcon fontSize={ 'tiny' } /> }
93
+ isLinked={ isLinked }
94
+ extendedValues={ extendedValues }
95
+ />
96
+ </Grid>
88
97
  </Grid>
89
- </Grid>
90
- <Grid container gap={ 1 } alignItems="center">
91
- <Grid item xs={ 12 }>
92
- <ControlLabel>{ __( 'Left', 'elementor' ) }</ControlLabel>
98
+ <Grid container gap={ 1 } alignItems="center">
99
+ <Grid item xs={ 12 }>
100
+ <ControlLabel>{ __( 'Left', 'elementor' ) }</ControlLabel>
101
+ </Grid>
102
+ <Grid item xs={ 12 }>
103
+ <Control
104
+ bind={ 'left' }
105
+ startIcon={ <SideLeftIcon fontSize={ 'tiny' } /> }
106
+ isLinked={ isLinked }
107
+ extendedValues={ extendedValues }
108
+ />
109
+ </Grid>
93
110
  </Grid>
94
- <Grid item xs={ 12 }>
95
- <Control
96
- bind={ 'left' }
97
- startIcon={ <SideLeftIcon fontSize={ 'tiny' } /> }
98
- isLinked={ isLinked }
99
- />
100
- </Grid>
101
- </Grid>
102
- </Stack>
103
- </PropProvider>
104
- );
105
- } );
111
+ </Stack>
112
+ </PropProvider>
113
+ );
114
+ }
115
+ );
106
116
 
107
- const Control = ( { bind, startIcon, isLinked }: { bind: PropKey; startIcon: React.ReactNode; isLinked: boolean } ) => {
117
+ const Control = ( {
118
+ bind,
119
+ startIcon,
120
+ isLinked,
121
+ extendedValues,
122
+ }: {
123
+ bind: PropKey;
124
+ startIcon: React.ReactNode;
125
+ isLinked: boolean;
126
+ extendedValues?: ExtendedValue[];
127
+ } ) => {
108
128
  if ( isLinked ) {
109
- return <SizeControl startIcon={ startIcon } />;
129
+ return <SizeControl startIcon={ startIcon } extendedValues={ extendedValues } />;
110
130
  }
111
131
 
112
132
  return (
113
133
  <PropKeyProvider bind={ bind }>
114
- <SizeControl startIcon={ startIcon } />
134
+ <SizeControl startIcon={ startIcon } extendedValues={ extendedValues } />
115
135
  </PropKeyProvider>
116
136
  );
117
137
  };