@elementor/editor-editing-panel 1.0.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 (117) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/dist/index.d.mts +10 -19
  3. package/dist/index.d.ts +10 -19
  4. package/dist/index.js +1283 -1751
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +1305 -1762
  7. package/dist/index.mjs.map +1 -1
  8. package/package.json +12 -12
  9. package/src/components/add-or-remove-content.tsx +3 -3
  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 +5 -3
  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 +9 -6
  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 +11 -11
  24. package/src/components/style-sections/background-section/background-color-field.tsx +4 -4
  25. package/src/components/style-sections/background-section/background-section.tsx +9 -7
  26. package/src/components/style-sections/border-section/border-color-field.tsx +4 -4
  27. package/src/components/style-sections/border-section/border-field.tsx +4 -3
  28. package/src/components/style-sections/border-section/border-radius-field.tsx +4 -3
  29. package/src/components/style-sections/border-section/border-section.tsx +7 -10
  30. package/src/components/style-sections/border-section/border-style-field.tsx +4 -4
  31. package/src/components/style-sections/border-section/border-width-field.tsx +4 -3
  32. package/src/components/style-sections/effects-section/effects-section.tsx +7 -10
  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 +6 -6
  38. package/src/components/style-sections/position-section/position-field.tsx +4 -4
  39. package/src/components/style-sections/position-section/position-section.tsx +45 -15
  40. package/src/components/style-sections/position-section/z-index-field.tsx +4 -4
  41. package/src/components/style-sections/size-section/overflow-field.tsx +8 -8
  42. package/src/components/style-sections/size-section/size-section.tsx +33 -26
  43. package/src/components/style-sections/spacing-section/spacing-section.tsx +11 -13
  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 +4 -4
  46. package/src/components/style-sections/typography-section/font-weight-field.tsx +4 -4
  47. package/src/components/style-sections/typography-section/letter-spacing-field.tsx +4 -4
  48. package/src/components/style-sections/typography-section/text-alignment-field.tsx +9 -9
  49. package/src/components/style-sections/typography-section/text-color-field.tsx +4 -4
  50. package/src/components/style-sections/typography-section/text-direction-field.tsx +7 -7
  51. package/src/components/style-sections/typography-section/text-stroke-field.tsx +3 -3
  52. package/src/components/style-sections/typography-section/text-style-field.tsx +5 -4
  53. package/src/components/style-sections/typography-section/transform-field.tsx +23 -9
  54. package/src/components/style-sections/typography-section/typography-section.tsx +26 -27
  55. package/src/components/style-sections/typography-section/word-spacing-field.tsx +4 -4
  56. package/src/components/style-tab.tsx +67 -31
  57. package/src/contexts/classes-prop-context.tsx +1 -1
  58. package/src/contexts/element-context.tsx +2 -2
  59. package/src/contexts/style-context.tsx +6 -5
  60. package/src/control-replacement.tsx +1 -1
  61. package/src/controls-actions.ts +3 -2
  62. package/src/controls-registry/control-type-container.tsx +3 -2
  63. package/src/controls-registry/control.tsx +2 -1
  64. package/src/controls-registry/controls-registry.tsx +8 -1
  65. package/src/controls-registry/settings-field.tsx +5 -4
  66. package/src/controls-registry/styles-field.tsx +3 -2
  67. package/src/dynamics/components/dynamic-selection-control.tsx +15 -14
  68. package/src/dynamics/components/dynamic-selection.tsx +9 -8
  69. package/src/dynamics/dynamic-control.tsx +4 -4
  70. package/src/dynamics/hooks/use-dynamic-tag.ts +3 -2
  71. package/src/dynamics/hooks/use-prop-dynamic-action.tsx +6 -5
  72. package/src/dynamics/hooks/use-prop-dynamic-tags.ts +3 -2
  73. package/src/dynamics/init.ts +5 -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 -2
  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 +25 -4
  83. package/src/index.ts +1 -1
  84. package/src/init.ts +5 -4
  85. package/src/panel.ts +1 -0
  86. package/src/popover-action.tsx +1 -1
  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} +1 -1
  90. package/src/sync/types.ts +20 -21
  91. package/src/components/accordion-section.tsx +0 -26
  92. package/src/components/control-label.tsx +0 -10
  93. package/src/controls/bound-prop-context.tsx +0 -30
  94. package/src/controls/components/control-toggle-button-group.tsx +0 -68
  95. package/src/controls/components/repeater.tsx +0 -197
  96. package/src/controls/components/text-field-inner-selection.tsx +0 -75
  97. package/src/controls/control-actions/control-actions-context.tsx +0 -27
  98. package/src/controls/control-actions/control-actions-menu.ts +0 -7
  99. package/src/controls/control-actions/control-actions.tsx +0 -31
  100. package/src/controls/controls/box-shadow-repeater-control.tsx +0 -210
  101. package/src/controls/controls/color-control.tsx +0 -25
  102. package/src/controls/controls/equal-unequal-sizes-control.tsx +0 -196
  103. package/src/controls/controls/image-control.tsx +0 -58
  104. package/src/controls/controls/image-media-control.tsx +0 -64
  105. package/src/controls/controls/linked-dimensions-control.tsx +0 -139
  106. package/src/controls/controls/number-control.tsx +0 -29
  107. package/src/controls/controls/select-control.tsx +0 -30
  108. package/src/controls/controls/size-control.tsx +0 -71
  109. package/src/controls/controls/stroke-control.tsx +0 -105
  110. package/src/controls/controls/text-area-control.tsx +0 -31
  111. package/src/controls/controls/text-control.tsx +0 -17
  112. package/src/controls/controls/toggle-control.tsx +0 -26
  113. package/src/controls/create-control-replacement.tsx +0 -53
  114. package/src/controls/create-control.tsx +0 -40
  115. package/src/controls/hooks/use-sync-external-state.tsx +0 -51
  116. package/src/controls/index.ts +0 -24
  117. package/src/dynamics/hooks/use-prop-value-history.ts +0 -26
@@ -1,196 +0,0 @@
1
- import * as React from 'react';
2
- import { ReactNode, useId, useRef } from 'react';
3
- import { PropValue, TransformablePropValue } from '@elementor/editor-props';
4
- import { bindPopover, bindToggle, Grid, Popover, Stack, ToggleButton, usePopupState } from '@elementor/ui';
5
- import { __ } from '@wordpress/i18n';
6
- import { ControlLabel } from '../../components/control-label';
7
- import { BoundPropProvider, SizeControl, SizeControlValue, useBoundProp } from '../index';
8
-
9
- type MultiSizePropValue< TMultiPropType extends string > = TransformablePropValue<
10
- TMultiPropType,
11
- Record< string, SizeControlValue >
12
- >;
13
-
14
- type Item< TMultiPropType extends string, TPropValue extends MultiSizePropValue< TMultiPropType > > = {
15
- icon: ReactNode;
16
- label: string;
17
- bind: keyof TPropValue[ 'value' ];
18
- };
19
-
20
- export type EqualUnequalItems<
21
- TMultiPropType extends string,
22
- TPropValue extends MultiSizePropValue< TMultiPropType >,
23
- > = [
24
- Item< TMultiPropType, TPropValue >,
25
- Item< TMultiPropType, TPropValue >,
26
- Item< TMultiPropType, TPropValue >,
27
- Item< TMultiPropType, TPropValue >,
28
- ];
29
-
30
- type Props< TMultiPropType extends string, TPropValue extends MultiSizePropValue< TMultiPropType > > = {
31
- label: string;
32
- icon: ReactNode;
33
- items: EqualUnequalItems< TMultiPropType, TPropValue >;
34
- multiSizeType: TMultiPropType;
35
- };
36
-
37
- function hasMixedSizes( values: SizeControlValue[] ): boolean {
38
- const [ firstValue, ...restValues ] = values;
39
-
40
- return restValues.some(
41
- ( value ) => value?.value?.size !== firstValue?.value?.size || value?.value?.unit !== firstValue?.value?.unit
42
- );
43
- }
44
-
45
- export function EqualUnequalSizesControl<
46
- TMultiPropType extends string,
47
- TPropValue extends MultiSizePropValue< TMultiPropType >,
48
- >( { label, icon, items, multiSizeType }: Props< TMultiPropType, TPropValue > ) {
49
- const popupId = useId();
50
- const controlRef = useRef< HTMLElement >( null );
51
- const { value: controlValue, setValue: setControlValue } = useBoundProp< TPropValue >();
52
-
53
- const actualValue: TPropValue[ 'value' ] = controlValue?.value ?? {};
54
- const setActualValue = ( newValue: TPropValue[ 'value' ] ) => {
55
- setControlValue( { $$type: multiSizeType, value: newValue } as TPropValue );
56
- };
57
-
58
- const setNestedProp = ( item: Item< TMultiPropType, TPropValue >, newValue: PropValue ) => {
59
- const { bind } = item;
60
-
61
- const newValues = {
62
- ...actualValue,
63
- [ bind ]: newValue,
64
- };
65
-
66
- setActualValue( newValues );
67
- };
68
-
69
- const setEqualValues = ( newValue: PropValue ) => {
70
- const equalValues = items.reduce( ( values: TPropValue[ 'value' ], item ) => {
71
- return {
72
- ...values,
73
- [ item.bind ]: newValue,
74
- };
75
- }, {} );
76
-
77
- setActualValue( equalValues );
78
- };
79
-
80
- const popupState = usePopupState( {
81
- variant: 'popover',
82
- popupId,
83
- } );
84
-
85
- return (
86
- <>
87
- <Grid container alignItems="center" ref={ controlRef }>
88
- <Grid item xs={ 6 }>
89
- <ControlLabel>{ label }</ControlLabel>
90
- </Grid>
91
- <Grid item xs={ 6 }>
92
- <EqualValuesControl
93
- value={ actualValue }
94
- setValue={ setEqualValues }
95
- iconButton={
96
- <ToggleButton
97
- size={ 'tiny' }
98
- value={ 'check' }
99
- sx={ { marginLeft: 'auto' } }
100
- { ...bindToggle( popupState ) }
101
- selected={ popupState.isOpen }
102
- >
103
- { icon }
104
- </ToggleButton>
105
- }
106
- />
107
- </Grid>
108
- </Grid>
109
- <Popover
110
- disablePortal
111
- disableScrollLock
112
- anchorOrigin={ {
113
- vertical: 'bottom',
114
- horizontal: 'right',
115
- } }
116
- transformOrigin={ {
117
- vertical: 'top',
118
- horizontal: 'right',
119
- } }
120
- { ...bindPopover( popupState ) }
121
- slotProps={ {
122
- paper: { sx: { mt: 0.5, p: 2, pt: 1, width: controlRef.current?.getBoundingClientRect().width } },
123
- } }
124
- >
125
- <Stack gap={ 1.5 }>
126
- <Grid container spacing={ 2 } alignItems="center">
127
- <NestedValueControl item={ items[ 0 ] } value={ actualValue } setNestedProp={ setNestedProp } />
128
- <NestedValueControl item={ items[ 1 ] } value={ actualValue } setNestedProp={ setNestedProp } />
129
- </Grid>
130
- <Grid container spacing={ 2 } alignItems="center">
131
- <NestedValueControl item={ items[ 3 ] } value={ actualValue } setNestedProp={ setNestedProp } />
132
- <NestedValueControl item={ items[ 2 ] } value={ actualValue } setNestedProp={ setNestedProp } />
133
- </Grid>
134
- </Stack>
135
- </Popover>
136
- </>
137
- );
138
- }
139
-
140
- const NestedValueControl = < TMultiPropType extends string, TPropValue extends MultiSizePropValue< TMultiPropType > >( {
141
- item,
142
- value,
143
- setNestedProp,
144
- }: {
145
- item: Item< TMultiPropType, TPropValue >;
146
- value: TPropValue[ 'value' ] | undefined;
147
- setNestedProp: ( item: Item< TMultiPropType, TPropValue >, newValue: PropValue ) => void;
148
- } ) => {
149
- const { bind } = item;
150
-
151
- const nestedValue = value?.[ bind ] ? value[ bind ] : undefined;
152
-
153
- return (
154
- <BoundPropProvider bind={ '' } setValue={ ( val ) => setNestedProp( item, val ) } value={ nestedValue }>
155
- <Grid item xs={ 6 }>
156
- <Grid container spacing={ 1 } alignItems="center">
157
- <Grid item xs={ 12 }>
158
- <ControlLabel>{ item.label }</ControlLabel>
159
- </Grid>
160
- <Grid item xs={ 12 }>
161
- <SizeControl startIcon={ item.icon } />
162
- </Grid>
163
- </Grid>
164
- </Grid>
165
- </BoundPropProvider>
166
- );
167
- };
168
-
169
- const EqualValuesControl = <
170
- TMultiPropType extends string,
171
- TPropValue extends MultiSizePropValue< TMultiPropType >[ 'value' ],
172
- >( {
173
- value,
174
- setValue,
175
- iconButton,
176
- }: {
177
- value: TPropValue | undefined;
178
- setValue: ( newValue: TPropValue ) => void;
179
- iconButton: ReactNode;
180
- } ) => {
181
- const values = Object.values( value ?? {} ) as SizeControlValue[];
182
- const isMixed = hasMixedSizes( values );
183
-
184
- return (
185
- <BoundPropProvider
186
- bind={ '' }
187
- setValue={ ( val ) => setValue( val as TPropValue ) }
188
- value={ isMixed ? undefined : values[ 0 ] }
189
- >
190
- <Stack direction="row" alignItems="center" gap={ 1 }>
191
- <SizeControl placeholder={ __( 'MIXED', 'elementor' ) } />
192
- { iconButton }
193
- </Stack>
194
- </BoundPropProvider>
195
- );
196
- };
@@ -1,58 +0,0 @@
1
- import * as React from 'react';
2
- import { __ } from '@wordpress/i18n';
3
- import { BoundPropProvider, useBoundProp } from '../bound-prop-context';
4
- import { Grid, Stack } from '@elementor/ui';
5
- import { PropValue, ImagePropValue, SizePropValue, ImageSrcPropValue } from '@elementor/editor-props';
6
- import { ImageMediaControl } from './image-media-control';
7
- import { SelectControl } from './select-control';
8
- import { createControl } from '../create-control';
9
- import { ControlLabel } from '../../components/control-label';
10
-
11
- type SetContextValue = ( v: PropValue ) => void;
12
-
13
- export type ImageControlProps = {
14
- sizes: { label: string; value: string }[];
15
- };
16
-
17
- export const ImageControl = createControl( ( props: ImageControlProps ) => {
18
- const { value, setValue } = useBoundProp< ImagePropValue | undefined >();
19
- const { src, size } = value?.value || {};
20
-
21
- const setImageSrc = ( newValue: ImageSrcPropValue ) => {
22
- setValue( {
23
- $$type: 'image',
24
- value: {
25
- src: newValue,
26
- size: size as SizePropValue,
27
- },
28
- } );
29
- };
30
-
31
- const setImageSize = ( newValue: SizePropValue ) => {
32
- setValue( {
33
- $$type: 'image',
34
- value: {
35
- src: src as ImageSrcPropValue,
36
- size: newValue,
37
- },
38
- } );
39
- };
40
-
41
- return (
42
- <Stack gap={ 2 }>
43
- <BoundPropProvider value={ src } setValue={ setImageSrc as SetContextValue } bind={ 'src' }>
44
- <ImageMediaControl />
45
- </BoundPropProvider>
46
- <BoundPropProvider value={ size } setValue={ setImageSize as SetContextValue } bind={ 'size' }>
47
- <Grid container spacing={ 1 } alignItems="center">
48
- <Grid item xs={ 6 }>
49
- <ControlLabel> { __( 'Image Resolution', 'elementor' ) }</ControlLabel>
50
- </Grid>
51
- <Grid item xs={ 6 }>
52
- <SelectControl options={ props.sizes } />
53
- </Grid>
54
- </Grid>
55
- </BoundPropProvider>
56
- </Stack>
57
- );
58
- } );
@@ -1,64 +0,0 @@
1
- import * as React from 'react';
2
- import { __ } from '@wordpress/i18n';
3
- import { ImageSrcPropValue } from '@elementor/editor-props';
4
- import { UploadIcon } from '@elementor/icons';
5
- import { Button, Card, CardMedia, CardOverlay, Stack } from '@elementor/ui';
6
- import { useWpMediaAttachment, useWpMediaFrame } from '@elementor/wp-media';
7
- import { useBoundProp } from '../bound-prop-context';
8
- import ControlActions from '../control-actions/control-actions';
9
- import { createControl } from '../create-control';
10
-
11
- export const ImageMediaControl = createControl( () => {
12
- const { value, setValue } = useBoundProp< ImageSrcPropValue >();
13
- const { id, url } = value?.value ?? {};
14
-
15
- const { data: attachment } = useWpMediaAttachment( id?.value || null );
16
- const src = attachment?.url ?? url;
17
-
18
- const { open } = useWpMediaFrame( {
19
- types: [ 'image' ],
20
- multiple: false,
21
- selected: id?.value || null,
22
- onSelect: ( selectedAttachment ) => {
23
- setValue( {
24
- $$type: 'image-src',
25
- value: {
26
- id: {
27
- $$type: 'image-attachment-id',
28
- value: selectedAttachment.id,
29
- },
30
- url: null,
31
- },
32
- } );
33
- },
34
- } );
35
-
36
- return (
37
- <Card variant="outlined">
38
- <CardMedia image={ src } sx={ { height: 150 } } />
39
- <CardOverlay>
40
- <ControlActions>
41
- <Stack gap={ 0.5 }>
42
- <Button
43
- size="tiny"
44
- color="inherit"
45
- variant="outlined"
46
- onClick={ () => open( { mode: 'browse' } ) }
47
- >
48
- { __( 'Select Image', 'elementor' ) }
49
- </Button>
50
- <Button
51
- size="tiny"
52
- variant="text"
53
- color="inherit"
54
- startIcon={ <UploadIcon /> }
55
- onClick={ () => open( { mode: 'upload' } ) }
56
- >
57
- { __( 'Upload Image', 'elementor' ) }
58
- </Button>
59
- </Stack>
60
- </ControlActions>
61
- </CardOverlay>
62
- </Card>
63
- );
64
- } );
@@ -1,139 +0,0 @@
1
- import * as React from 'react';
2
- import { __ } from '@wordpress/i18n';
3
- import { Grid, Stack, ToggleButton } from '@elementor/ui';
4
- import { PropValue, LinkedDimensionsPropValue } from '@elementor/editor-props';
5
- import { DetachIcon, LinkIcon, SideBottomIcon, SideLeftIcon, SideRightIcon, SideTopIcon } from '@elementor/icons';
6
- import { createControl } from '../create-control';
7
- import { ControlLabel } from '../../components/control-label';
8
- import { SizeControl } from './size-control';
9
- import { BoundPropProvider, useBoundProp } from '../bound-prop-context';
10
-
11
- export type Position = 'top' | 'right' | 'bottom' | 'left';
12
-
13
- export const LinkedDimensionsControl = createControl( ( { label }: { label: string } ) => {
14
- const { value, setValue } = useBoundProp< LinkedDimensionsPropValue >();
15
- const { top, right, bottom, left, isLinked = true } = value?.value || {};
16
-
17
- const setLinkedValue = ( position: Position, newValue: PropValue ) => {
18
- const updatedValue = {
19
- isLinked,
20
- top: isLinked ? newValue : top,
21
- right: isLinked ? newValue : right,
22
- bottom: isLinked ? newValue : bottom,
23
- left: isLinked ? newValue : left,
24
- [ position ]: newValue,
25
- };
26
-
27
- setValue( {
28
- $$type: 'linked-dimensions',
29
- value: updatedValue,
30
- } );
31
- };
32
-
33
- const toggleLinked = () => {
34
- const updatedValue = {
35
- isLinked: ! isLinked,
36
- top,
37
- right: ! isLinked ? top : right,
38
- bottom: ! isLinked ? top : bottom,
39
- left: ! isLinked ? top : left,
40
- };
41
-
42
- setValue( {
43
- $$type: 'linked-dimensions',
44
- value: updatedValue,
45
- } );
46
- };
47
-
48
- const LinkedIcon = isLinked ? LinkIcon : DetachIcon;
49
-
50
- return (
51
- <>
52
- <Stack direction="row" gap={ 2 }>
53
- <ControlLabel>{ label }</ControlLabel>
54
- <ToggleButton
55
- aria-label={ __( 'Link Inputs', 'elementor' ) }
56
- size={ 'tiny' }
57
- value={ 'check' }
58
- selected={ isLinked }
59
- sx={ { marginLeft: 'auto' } }
60
- onChange={ toggleLinked }
61
- >
62
- <LinkedIcon fontSize={ 'tiny' } />
63
- </ToggleButton>
64
- </Stack>
65
- <Stack direction="row" gap={ 2 }>
66
- <Grid container spacing={ 1 } alignItems="center">
67
- <Grid item xs={ 12 }>
68
- <ControlLabel>{ __( 'Top', 'elementor' ) }</ControlLabel>
69
- </Grid>
70
- <Grid item xs={ 12 }>
71
- <Control
72
- bind={ 'top' }
73
- value={ top }
74
- setValue={ setLinkedValue }
75
- startIcon={ <SideTopIcon fontSize={ 'tiny' } /> }
76
- />
77
- </Grid>
78
- </Grid>
79
- <Grid container spacing={ 1 } alignItems="center">
80
- <Grid item xs={ 12 }>
81
- <ControlLabel>{ __( 'Right', 'elementor' ) }</ControlLabel>
82
- </Grid>
83
- <Grid item xs={ 12 }>
84
- <Control
85
- bind={ 'right' }
86
- value={ right }
87
- setValue={ setLinkedValue }
88
- startIcon={ <SideRightIcon fontSize={ 'tiny' } /> }
89
- />
90
- </Grid>
91
- </Grid>
92
- </Stack>
93
- <Stack direction="row" gap={ 2 }>
94
- <Grid container spacing={ 1 } alignItems="center">
95
- <Grid item xs={ 12 }>
96
- <ControlLabel>{ __( 'Bottom', 'elementor' ) }</ControlLabel>
97
- </Grid>
98
- <Grid item xs={ 12 }>
99
- <Control
100
- bind={ 'bottom' }
101
- value={ bottom }
102
- setValue={ setLinkedValue }
103
- startIcon={ <SideBottomIcon fontSize={ 'tiny' } /> }
104
- />
105
- </Grid>
106
- </Grid>
107
- <Grid container spacing={ 1 } alignItems="center">
108
- <Grid item xs={ 12 }>
109
- <ControlLabel>{ __( 'Left', 'elementor' ) }</ControlLabel>
110
- </Grid>
111
- <Grid item xs={ 12 }>
112
- <Control
113
- bind={ 'left' }
114
- value={ left }
115
- setValue={ setLinkedValue }
116
- startIcon={ <SideLeftIcon fontSize={ 'tiny' } /> }
117
- />
118
- </Grid>
119
- </Grid>
120
- </Stack>
121
- </>
122
- );
123
- } );
124
-
125
- const Control = ( {
126
- bind,
127
- startIcon,
128
- value,
129
- setValue,
130
- }: {
131
- bind: Position;
132
- value: PropValue;
133
- startIcon: React.ReactNode;
134
- setValue: ( bind: Position, newValue: PropValue ) => void;
135
- } ) => (
136
- <BoundPropProvider setValue={ ( newValue ) => setValue( bind, newValue ) } value={ value } bind={ bind }>
137
- <SizeControl startIcon={ startIcon } />
138
- </BoundPropProvider>
139
- );
@@ -1,29 +0,0 @@
1
- import * as React from 'react';
2
- import { TextField } from '@elementor/ui';
3
- import { useBoundProp } from '../bound-prop-context';
4
- import ControlActions from '../control-actions/control-actions';
5
- import { createControl } from '../create-control';
6
-
7
- const isEmptyOrNaN = ( value?: string | number ) =>
8
- value === undefined || value === '' || Number.isNaN( Number( value ) );
9
-
10
- export const NumberControl = createControl( ( { placeholder }: { placeholder?: string } ) => {
11
- const { value, setValue } = useBoundProp< number | undefined >();
12
-
13
- const handleChange = ( event: React.ChangeEvent< HTMLInputElement > ) => {
14
- const eventValue: string = event.target.value;
15
- setValue( isEmptyOrNaN( eventValue ) ? undefined : Number( eventValue ) );
16
- };
17
-
18
- return (
19
- <ControlActions>
20
- <TextField
21
- size="tiny"
22
- type="number"
23
- value={ isEmptyOrNaN( value ) ? '' : value }
24
- onChange={ handleChange }
25
- placeholder={ placeholder }
26
- />
27
- </ControlActions>
28
- );
29
- } );
@@ -1,30 +0,0 @@
1
- import * as React from 'react';
2
- import { PropValue } from '@elementor/editor-props';
3
- import { MenuItem, Select, SelectChangeEvent } from '@elementor/ui';
4
- import { useBoundProp } from '../bound-prop-context';
5
- import ControlActions from '../control-actions/control-actions';
6
- import { createControl } from '../create-control';
7
-
8
- type Props< T > = {
9
- options: Array< { label: string; value: T; disabled?: boolean } >;
10
- };
11
-
12
- export const SelectControl = createControl( < T extends PropValue >( { options }: Props< T > ) => {
13
- const { value, setValue } = useBoundProp< T >();
14
-
15
- const handleChange = ( event: SelectChangeEvent< T > ) => {
16
- setValue( event.target.value as T );
17
- };
18
-
19
- return (
20
- <ControlActions>
21
- <Select displayEmpty size="tiny" value={ value ?? '' } onChange={ handleChange } fullWidth>
22
- { options.map( ( { label, ...props } ) => (
23
- <MenuItem key={ props.value } { ...props }>
24
- { label }
25
- </MenuItem>
26
- ) ) }
27
- </Select>
28
- </ControlActions>
29
- );
30
- } );
@@ -1,71 +0,0 @@
1
- import * as React from 'react';
2
- import { SizePropValue, TransformablePropValue } from '@elementor/editor-props';
3
- import { InputAdornment } from '@elementor/ui';
4
- import { useBoundProp } from '../bound-prop-context';
5
- import { useSyncExternalState } from '../hooks/use-sync-external-state';
6
- import { SelectionEndAdornment, TextFieldInnerSelection } from '../components/text-field-inner-selection';
7
- import ControlActions from '../control-actions/control-actions';
8
- import { createControl } from '../create-control';
9
-
10
- export type Unit = 'px' | '%' | 'em' | 'rem' | 'vw' | 'vh';
11
-
12
- const defaultUnits: Unit[] = [ 'px', '%', 'em', 'rem', 'vw', 'vh' ];
13
-
14
- export type SizeControlProps = {
15
- placeholder?: string;
16
- startIcon?: React.ReactNode;
17
- units?: Unit[];
18
- };
19
-
20
- export type SizeControlValue = TransformablePropValue< 'size', { unit: Unit; size: number } >;
21
-
22
- export const SizeControl = createControl( ( { units = defaultUnits, placeholder, startIcon }: SizeControlProps ) => {
23
- const { value, setValue } = useBoundProp< SizePropValue | undefined >();
24
-
25
- const [ state, setState ] = useSyncExternalState< SizePropValue >( {
26
- external: value,
27
- setExternal: setValue,
28
- persistWhen: ( controlValue ) => !! controlValue?.value.size || controlValue?.value.size === 0,
29
- fallback: ( controlValue ) => ( {
30
- $$type: 'size',
31
- value: { unit: controlValue?.value.unit || 'px', size: NaN },
32
- } ),
33
- } );
34
-
35
- const handleUnitChange = ( unit: Unit ) => {
36
- setState( ( prev ) => ( {
37
- ...prev,
38
- value: {
39
- ...prev.value,
40
- unit,
41
- },
42
- } ) );
43
- };
44
-
45
- const handleSizeChange = ( event: React.ChangeEvent< HTMLInputElement > ) => {
46
- const { value: size } = event.target;
47
-
48
- setState( ( prev ) => ( {
49
- ...prev,
50
- value: {
51
- ...prev.value,
52
- size: size || size === '0' ? parseFloat( size ) : NaN,
53
- },
54
- } ) );
55
- };
56
-
57
- return (
58
- <ControlActions>
59
- <TextFieldInnerSelection
60
- endAdornment={
61
- <SelectionEndAdornment options={ units } onClick={ handleUnitChange } value={ state.value.unit } />
62
- }
63
- placeholder={ placeholder }
64
- startAdornment={ startIcon ?? <InputAdornment position="start">{ startIcon }</InputAdornment> }
65
- type="number"
66
- value={ Number.isNaN( state.value.size ) ? '' : state.value.size }
67
- onChange={ handleSizeChange }
68
- />
69
- </ControlActions>
70
- );
71
- } );
@@ -1,105 +0,0 @@
1
- import * as React from 'react';
2
- import { __ } from '@wordpress/i18n';
3
- import { Grid, Stack } from '@elementor/ui';
4
- import { createControl } from '../create-control';
5
- import { SizeControl, Unit } from './size-control';
6
- import { ControlLabel } from '../../components/control-label';
7
- import { ColorControl } from './color-control';
8
- import { PropValue, StrokePropValue, TransformablePropValue } from '@elementor/editor-props';
9
- import { BoundPropProvider, useBoundProp } from '../bound-prop-context';
10
-
11
- type SetContextValue = ( v: PropValue ) => void;
12
-
13
- const defaultStrokeControlValue: StrokePropValue = {
14
- $$type: 'stroke',
15
- value: {
16
- color: {
17
- $$type: 'color',
18
- value: '#000000',
19
- },
20
- width: {
21
- $$type: 'size',
22
- value: {
23
- unit: 'px',
24
- size: NaN,
25
- },
26
- },
27
- },
28
- };
29
-
30
- const units: Unit[] = [ 'px', 'em', 'rem' ];
31
-
32
- export const StrokeControl = createControl( () => {
33
- const { value, setValue } = useBoundProp< StrokePropValue >( defaultStrokeControlValue );
34
-
35
- const setStrokeWidth = ( newValue: TransformablePropValue< 'size', { unit: Unit; size: number } > ) => {
36
- const updatedValue = {
37
- ...( value?.value ?? defaultStrokeControlValue.value ),
38
- width: newValue,
39
- };
40
-
41
- setValue( {
42
- $$type: 'stroke',
43
- value: updatedValue,
44
- } );
45
- };
46
-
47
- const setStrokeColor = ( newValue: TransformablePropValue< 'color', string > ) => {
48
- const updatedValue = {
49
- ...( value?.value ?? defaultStrokeControlValue.value ),
50
- color: newValue,
51
- };
52
-
53
- setValue( {
54
- $$type: 'stroke',
55
- value: updatedValue,
56
- } );
57
- };
58
-
59
- return (
60
- <Stack gap={ 1.5 }>
61
- <Control
62
- bind="width"
63
- label={ __( 'Stroke Width', 'elementor' ) }
64
- value={ value?.value.width ?? defaultStrokeControlValue.value.width }
65
- setValue={ setStrokeWidth }
66
- >
67
- <SizeControl units={ units } />
68
- </Control>
69
-
70
- <Control
71
- bind="color"
72
- label={ __( 'Stroke Color', 'elementor' ) }
73
- value={ value?.value.color ?? defaultStrokeControlValue.value.color }
74
- setValue={ setStrokeColor }
75
- >
76
- <ColorControl />
77
- </Control>
78
- </Stack>
79
- );
80
- } );
81
-
82
- const Control = < T extends PropValue >( {
83
- bind,
84
- value,
85
- setValue,
86
- label,
87
- children,
88
- }: {
89
- bind: string;
90
- value: T;
91
- setValue: ( v: T ) => void;
92
- label: string;
93
- children: React.ReactNode;
94
- } ) => (
95
- <BoundPropProvider bind={ bind } value={ value } setValue={ setValue as SetContextValue }>
96
- <Grid container spacing={ 1 } alignItems="center">
97
- <Grid item xs={ 6 }>
98
- <ControlLabel>{ label }</ControlLabel>
99
- </Grid>
100
- <Grid item xs={ 6 }>
101
- { children }
102
- </Grid>
103
- </Grid>
104
- </BoundPropProvider>
105
- );