@elementor/editor-editing-panel 0.17.0 → 0.19.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/CHANGELOG.md +45 -0
- package/dist/index.d.mts +28 -10
- package/dist/index.d.ts +28 -10
- package/dist/index.js +941 -398
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +918 -366
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -7
- package/src/components/editing-panel-error-fallback.tsx +12 -0
- package/src/components/editing-panel.tsx +23 -12
- package/src/components/settings-tab.tsx +8 -5
- package/src/components/style-sections/background-section/background-color-control.tsx +20 -0
- package/src/components/style-sections/background-section/background-section.tsx +15 -0
- package/src/components/style-sections/effects-section/box-shadow-repeater.tsx +224 -0
- package/src/components/style-sections/effects-section/effects-section.tsx +18 -0
- package/src/components/style-sections/position-section/z-index-control.tsx +11 -7
- package/src/components/style-sections/size-section.tsx +23 -20
- package/src/components/style-sections/spacing-section/linked-dimensions-control.tsx +62 -47
- package/src/components/style-sections/typography-section/font-size-control.tsx +10 -6
- package/src/components/style-sections/typography-section/font-weight-control.tsx +16 -12
- package/src/components/style-sections/typography-section/letter-spacing-control.tsx +10 -6
- package/src/components/style-sections/typography-section/text-alignment-control.tsx +12 -8
- package/src/components/style-sections/typography-section/text-color-control.tsx +10 -6
- package/src/components/style-sections/typography-section/text-direction-control.tsx +37 -0
- package/src/components/style-sections/typography-section/text-style-control.tsx +37 -34
- package/src/components/style-sections/typography-section/transform-control.tsx +14 -12
- package/src/components/style-sections/typography-section/typography-section.tsx +2 -0
- package/src/components/style-sections/typography-section/word-spacing-control.tsx +10 -6
- package/src/components/style-tab.tsx +10 -4
- package/src/control-replacement.tsx +3 -0
- package/src/controls/components/control-type-container.tsx +28 -0
- package/src/controls/components/repeater.tsx +197 -0
- package/src/controls/components/text-field-inner-selection.tsx +2 -2
- package/src/controls/control-actions/actions/popover-action.tsx +58 -0
- package/src/controls/control-actions/control-actions-menu.ts +8 -0
- package/src/controls/control-actions/control-actions.tsx +43 -0
- package/src/controls/control-context.tsx +1 -1
- package/src/controls/control-replacement.ts +16 -8
- package/src/controls/control-types/color-control.tsx +21 -18
- package/src/controls/control-types/image-control.tsx +56 -59
- package/src/controls/control-types/image-media-control.tsx +73 -0
- package/src/controls/control-types/number-control.tsx +13 -9
- package/src/controls/control-types/select-control.tsx +14 -10
- package/src/controls/control-types/size-control.tsx +18 -14
- package/src/controls/control-types/text-area-control.tsx +15 -11
- package/src/controls/control-types/text-control.tsx +9 -3
- package/src/controls/control-types/toggle-control.tsx +4 -3
- package/src/controls/control.tsx +1 -7
- package/src/controls/controls-registry.tsx +19 -10
- package/src/controls/create-control-replacement.tsx +53 -0
- package/src/controls/create-control.tsx +40 -0
- package/src/controls/hooks/use-style-control.ts +3 -3
- package/src/{hooks → controls/hooks}/use-widget-settings.ts +1 -1
- package/src/{props → controls/props}/is-transformable.ts +1 -2
- package/src/controls/props/types.ts +51 -0
- package/src/{contexts/element-context.tsx → controls/providers/element-provider.tsx} +4 -4
- package/src/controls/settings-control.tsx +7 -14
- package/src/controls/style-control.tsx +1 -1
- package/src/{sync → controls/sync}/get-container.ts +1 -1
- package/src/{sync → controls/sync}/update-settings.ts +1 -1
- package/src/controls/types.ts +39 -0
- package/src/dynamics/components/dynamic-selection-control.tsx +2 -2
- package/src/dynamics/components/dynamic-selection.tsx +6 -6
- package/src/dynamics/dynamic-control.tsx +2 -2
- package/src/dynamics/hooks/use-dynamic-tag.ts +2 -2
- package/src/dynamics/hooks/use-prop-dynamic-action.tsx +23 -0
- package/src/dynamics/hooks/use-prop-dynamic-tags.ts +7 -7
- package/src/dynamics/hooks/use-prop-value-history.ts +3 -3
- package/src/dynamics/init.ts +10 -1
- package/src/dynamics/types.ts +7 -3
- package/src/dynamics/utils.ts +17 -4
- package/src/hooks/use-element-style-prop.ts +3 -2
- package/src/hooks/use-element-styles.ts +1 -1
- package/src/hooks/use-element-type.ts +1 -1
- package/src/index.ts +3 -1
- package/src/sync/get-element-styles.ts +2 -2
- package/src/sync/get-selected-elements.ts +1 -1
- package/src/sync/types.ts +2 -1
- package/src/sync/update-style.ts +3 -2
- package/src/controls/components/control-container.tsx +0 -18
- package/src/types.ts +0 -68
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { bindPopover, bindToggle, IconButton, Popover, Stack, Tooltip, Typography, usePopupState } from '@elementor/ui';
|
|
3
|
+
import { ComponentType, ElementType as ReactElementType, useId } from 'react';
|
|
4
|
+
import { XIcon } from '@elementor/icons';
|
|
5
|
+
|
|
6
|
+
const SIZE = 'tiny';
|
|
7
|
+
|
|
8
|
+
export type PopoverActionProps = {
|
|
9
|
+
title: string;
|
|
10
|
+
visible?: boolean;
|
|
11
|
+
icon: ReactElementType;
|
|
12
|
+
popoverContent: ComponentType< { closePopover: () => void } >;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export default function PopoverAction( {
|
|
16
|
+
title,
|
|
17
|
+
visible = true,
|
|
18
|
+
icon: Icon,
|
|
19
|
+
popoverContent: PopoverContent,
|
|
20
|
+
}: PopoverActionProps ) {
|
|
21
|
+
const id = useId();
|
|
22
|
+
const popupState = usePopupState( {
|
|
23
|
+
variant: 'popover',
|
|
24
|
+
popupId: `elementor-popover-action-${ id }`,
|
|
25
|
+
} );
|
|
26
|
+
|
|
27
|
+
if ( ! visible ) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<>
|
|
33
|
+
<Tooltip placement="top" title={ title }>
|
|
34
|
+
<IconButton aria-label={ title } key={ id } size={ SIZE } { ...bindToggle( popupState ) }>
|
|
35
|
+
<Icon fontSize={ SIZE } />
|
|
36
|
+
</IconButton>
|
|
37
|
+
</Tooltip>
|
|
38
|
+
<Popover
|
|
39
|
+
disablePortal
|
|
40
|
+
disableScrollLock
|
|
41
|
+
anchorOrigin={ {
|
|
42
|
+
vertical: 'bottom',
|
|
43
|
+
horizontal: 'center',
|
|
44
|
+
} }
|
|
45
|
+
{ ...bindPopover( popupState ) }
|
|
46
|
+
>
|
|
47
|
+
<Stack direction="row" alignItems="center" pl={ 1.5 } pr={ 0.5 } py={ 1.5 }>
|
|
48
|
+
<Icon fontSize={ SIZE } sx={ { mr: 0.5 } } />
|
|
49
|
+
<Typography variant="subtitle2">{ title }</Typography>
|
|
50
|
+
<IconButton sx={ { ml: 'auto' } } size={ SIZE } onClick={ popupState.close }>
|
|
51
|
+
<XIcon fontSize={ SIZE } />
|
|
52
|
+
</IconButton>
|
|
53
|
+
</Stack>
|
|
54
|
+
<PopoverContent closePopover={ popupState.close } />
|
|
55
|
+
</Popover>
|
|
56
|
+
</>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { styled, UnstableFloatingActionBar } from '@elementor/ui';
|
|
3
|
+
import { PropsWithChildren } from 'react';
|
|
4
|
+
import { controlActionsMenu } from './control-actions-menu';
|
|
5
|
+
|
|
6
|
+
const { useMenuItems } = controlActionsMenu;
|
|
7
|
+
|
|
8
|
+
// CSS hack to hide empty floating bars.
|
|
9
|
+
const FloatingBar = styled( UnstableFloatingActionBar )`
|
|
10
|
+
& .MuiPaper-root:empty {
|
|
11
|
+
display: none;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// this is for a fix which would be added later on - to force the width externally
|
|
15
|
+
width: 100%;
|
|
16
|
+
& > :first-of-type {
|
|
17
|
+
width: 100%;
|
|
18
|
+
}
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
export type ControlActionsProps = PropsWithChildren< {
|
|
22
|
+
fullWidth?: boolean;
|
|
23
|
+
} >;
|
|
24
|
+
|
|
25
|
+
export default function ControlActions( { fullWidth = false, children }: ControlActionsProps ) {
|
|
26
|
+
const items = useMenuItems().default;
|
|
27
|
+
|
|
28
|
+
if ( items.length === 0 ) {
|
|
29
|
+
return children;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<FloatingBar
|
|
34
|
+
actions={ items.map( ( { MenuItem, id } ) => (
|
|
35
|
+
<MenuItem key={ id } />
|
|
36
|
+
) ) }
|
|
37
|
+
// TODO - work on a general layouting solution instead
|
|
38
|
+
sx={ fullWidth ? { width: '100%' } : undefined }
|
|
39
|
+
>
|
|
40
|
+
{ children }
|
|
41
|
+
</FloatingBar>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
@@ -1,26 +1,34 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ComponentType } from 'react';
|
|
2
|
+
import { PropValue } from './props/types';
|
|
3
|
+
import { useControl } from './control-context';
|
|
2
4
|
|
|
3
5
|
type ReplaceWhenParams = {
|
|
4
6
|
value: PropValue;
|
|
5
7
|
};
|
|
6
8
|
|
|
7
9
|
type ControlReplacement = {
|
|
8
|
-
component:
|
|
10
|
+
component: ComponentType;
|
|
9
11
|
condition: ( { value }: ReplaceWhenParams ) => boolean;
|
|
10
12
|
};
|
|
11
13
|
|
|
12
14
|
let controlReplacement: ControlReplacement | undefined;
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
controlReplacement = { component, condition };
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export const getControlReplacement = ( { value }: ReplaceWhenParams ) => {
|
|
16
|
+
const getControlReplacement = ( { value }: ReplaceWhenParams ) => {
|
|
19
17
|
let shouldReplace = false;
|
|
20
18
|
|
|
21
19
|
try {
|
|
22
|
-
shouldReplace = !! controlReplacement?.condition( { value } );
|
|
20
|
+
shouldReplace = !! controlReplacement?.condition( { value } ) && !! controlReplacement?.component;
|
|
23
21
|
} catch {}
|
|
24
22
|
|
|
25
23
|
return shouldReplace ? controlReplacement?.component : undefined;
|
|
26
24
|
};
|
|
25
|
+
|
|
26
|
+
export function replaceControl( { component, condition }: ControlReplacement ) {
|
|
27
|
+
controlReplacement = { component, condition };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function useControlReplacement() {
|
|
31
|
+
const { value } = useControl();
|
|
32
|
+
|
|
33
|
+
return getControlReplacement( { value } );
|
|
34
|
+
}
|
|
@@ -1,24 +1,27 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { UnstableColorPicker } from '@elementor/ui';
|
|
2
|
+
import { UnstableColorPicker, UnstableColorPickerProps } from '@elementor/ui';
|
|
3
3
|
import { useControl } from '../control-context';
|
|
4
|
+
import ControlActions from '../control-actions/control-actions';
|
|
5
|
+
import { createControl } from '../create-control';
|
|
6
|
+
import { TransformablePropValue } from '../props/types';
|
|
4
7
|
|
|
5
|
-
export
|
|
6
|
-
const { value, setValue } = useControl< string >();
|
|
8
|
+
export type ColorPropValue = TransformablePropValue< 'color', string >;
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
export const ColorControl = createControl(
|
|
11
|
+
( props: Partial< Omit< UnstableColorPickerProps, 'value' | 'onChange' > > ) => {
|
|
12
|
+
const { value, setValue } = useControl< ColorPropValue >();
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
const handleChange = ( selectedColor: string ) => {
|
|
15
|
+
setValue( {
|
|
16
|
+
$$type: 'color',
|
|
17
|
+
value: selectedColor,
|
|
18
|
+
} );
|
|
19
|
+
};
|
|
14
20
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
timer = setTimeout( () => func( ...args ), wait );
|
|
23
|
-
};
|
|
24
|
-
};
|
|
21
|
+
return (
|
|
22
|
+
<ControlActions>
|
|
23
|
+
<UnstableColorPicker size="tiny" { ...props } value={ value?.value } onChange={ handleChange } />
|
|
24
|
+
</ControlActions>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
);
|
|
@@ -1,69 +1,66 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import { useControl } from '../control-context';
|
|
4
|
-
import { UploadIcon } from '@elementor/icons';
|
|
2
|
+
import { Grid, Stack } from '@elementor/ui';
|
|
5
3
|
import { __ } from '@wordpress/i18n';
|
|
6
|
-
import {
|
|
4
|
+
import { ControlContext, useControl } from '../control-context';
|
|
5
|
+
import { type ImageSrc, ImageMediaControl } from './image-media-control';
|
|
6
|
+
import { PropValue, TransformablePropValue } from '../props/types';
|
|
7
|
+
import { SettingsControl } from '../settings-control';
|
|
8
|
+
import { SelectControl } from './select-control';
|
|
9
|
+
import { createControl } from '../create-control';
|
|
7
10
|
|
|
8
|
-
type Image =
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
type Image = TransformablePropValue<
|
|
12
|
+
'image',
|
|
13
|
+
{
|
|
14
|
+
src?: ImageSrc;
|
|
15
|
+
size?: string;
|
|
16
|
+
}
|
|
17
|
+
>;
|
|
18
|
+
|
|
19
|
+
type SetContextValue = ( v: PropValue ) => void;
|
|
20
|
+
|
|
21
|
+
export type ImageControlProps = {
|
|
22
|
+
sizes: { label: string; value: string }[];
|
|
19
23
|
};
|
|
20
24
|
|
|
21
|
-
export const ImageControl = () => {
|
|
25
|
+
export const ImageControl = createControl( ( props: ImageControlProps ) => {
|
|
22
26
|
const { value, setValue } = useControl< Image >();
|
|
23
|
-
const {
|
|
24
|
-
const src = attachment?.url ?? value?.value?.url;
|
|
27
|
+
const { src, size } = value?.value || {};
|
|
25
28
|
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
},
|
|
36
|
-
} );
|
|
37
|
-
},
|
|
38
|
-
} );
|
|
29
|
+
const setImageSrc = ( newValue: ImageSrc ) => {
|
|
30
|
+
setValue( {
|
|
31
|
+
$$type: 'image',
|
|
32
|
+
value: {
|
|
33
|
+
src: newValue,
|
|
34
|
+
size,
|
|
35
|
+
},
|
|
36
|
+
} );
|
|
37
|
+
};
|
|
39
38
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
open( { mode: 'browse' } );
|
|
50
|
-
} }
|
|
51
|
-
>
|
|
52
|
-
{ __( 'Select Image', 'elementor' ) }
|
|
53
|
-
</Button>
|
|
39
|
+
const setImageSize = ( newValue: string ) => {
|
|
40
|
+
setValue( {
|
|
41
|
+
$$type: 'image',
|
|
42
|
+
value: {
|
|
43
|
+
src,
|
|
44
|
+
size: newValue,
|
|
45
|
+
},
|
|
46
|
+
} );
|
|
47
|
+
};
|
|
54
48
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
49
|
+
return (
|
|
50
|
+
<Stack gap={ 2 }>
|
|
51
|
+
<ControlContext.Provider value={ { setValue: setImageSrc as SetContextValue, value: src, bind: 'src' } }>
|
|
52
|
+
<ImageMediaControl />
|
|
53
|
+
</ControlContext.Provider>
|
|
54
|
+
<ControlContext.Provider value={ { setValue: setImageSize as SetContextValue, value: size, bind: 'size' } }>
|
|
55
|
+
<Grid container spacing={ 1 } alignItems="center">
|
|
56
|
+
<Grid item xs={ 6 }>
|
|
57
|
+
<SettingsControl.Label> { __( 'Image Resolution', 'elementor' ) }</SettingsControl.Label>
|
|
58
|
+
</Grid>
|
|
59
|
+
<Grid item xs={ 6 }>
|
|
60
|
+
<SelectControl options={ props.sizes } />
|
|
61
|
+
</Grid>
|
|
62
|
+
</Grid>
|
|
63
|
+
</ControlContext.Provider>
|
|
64
|
+
</Stack>
|
|
68
65
|
);
|
|
69
|
-
};
|
|
66
|
+
} );
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Button, Card, CardMedia, CardOverlay, Stack } from '@elementor/ui';
|
|
3
|
+
import { UploadIcon } from '@elementor/icons';
|
|
4
|
+
import { useWpMediaAttachment, useWpMediaFrame } from '@elementor/wp-media';
|
|
5
|
+
import { __ } from '@wordpress/i18n';
|
|
6
|
+
import { useControl } from '../control-context';
|
|
7
|
+
import ControlActions from '../control-actions/control-actions';
|
|
8
|
+
import { createControl } from '../create-control';
|
|
9
|
+
import { TransformablePropValue } from '../props/types';
|
|
10
|
+
|
|
11
|
+
type ImageAttachmentID = TransformablePropValue< 'image-attachment-id', number >;
|
|
12
|
+
|
|
13
|
+
type Url = TransformablePropValue< 'url', string >;
|
|
14
|
+
|
|
15
|
+
export type ImageSrc = TransformablePropValue<
|
|
16
|
+
'image-src',
|
|
17
|
+
{ id: ImageAttachmentID; url: null } | { url: Url; id: null }
|
|
18
|
+
>;
|
|
19
|
+
|
|
20
|
+
export const ImageMediaControl = createControl( () => {
|
|
21
|
+
const { value, setValue } = useControl< ImageSrc >();
|
|
22
|
+
const { id, url } = value?.value ?? {};
|
|
23
|
+
|
|
24
|
+
const { data: attachment } = useWpMediaAttachment( id?.value || null );
|
|
25
|
+
const src = attachment?.url ?? url;
|
|
26
|
+
|
|
27
|
+
const { open } = useWpMediaFrame( {
|
|
28
|
+
types: [ 'image' ],
|
|
29
|
+
multiple: false,
|
|
30
|
+
selected: id?.value || null,
|
|
31
|
+
onSelect: ( selectedAttachment ) => {
|
|
32
|
+
setValue( {
|
|
33
|
+
$$type: 'image-src',
|
|
34
|
+
value: {
|
|
35
|
+
id: {
|
|
36
|
+
$$type: 'image-attachment-id',
|
|
37
|
+
value: selectedAttachment.id,
|
|
38
|
+
},
|
|
39
|
+
url: null,
|
|
40
|
+
},
|
|
41
|
+
} );
|
|
42
|
+
},
|
|
43
|
+
} );
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<Card variant="outlined">
|
|
47
|
+
<CardMedia image={ src } sx={ { height: 150 } } />
|
|
48
|
+
<CardOverlay>
|
|
49
|
+
<ControlActions>
|
|
50
|
+
<Stack gap={ 0.5 }>
|
|
51
|
+
<Button
|
|
52
|
+
size="tiny"
|
|
53
|
+
color="inherit"
|
|
54
|
+
variant="outlined"
|
|
55
|
+
onClick={ () => open( { mode: 'browse' } ) }
|
|
56
|
+
>
|
|
57
|
+
{ __( 'Select Image', 'elementor' ) }
|
|
58
|
+
</Button>
|
|
59
|
+
<Button
|
|
60
|
+
size="tiny"
|
|
61
|
+
variant="text"
|
|
62
|
+
color="inherit"
|
|
63
|
+
startIcon={ <UploadIcon /> }
|
|
64
|
+
onClick={ () => open( { mode: 'upload' } ) }
|
|
65
|
+
>
|
|
66
|
+
{ __( 'Upload Image', 'elementor' ) }
|
|
67
|
+
</Button>
|
|
68
|
+
</Stack>
|
|
69
|
+
</ControlActions>
|
|
70
|
+
</CardOverlay>
|
|
71
|
+
</Card>
|
|
72
|
+
);
|
|
73
|
+
} );
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { TextField } from '@elementor/ui';
|
|
3
3
|
import { useControl } from '../control-context';
|
|
4
|
+
import ControlActions from '../control-actions/control-actions';
|
|
5
|
+
import { createControl } from '../create-control';
|
|
4
6
|
|
|
5
7
|
const isEmptyOrNaN = ( value?: string | number ) =>
|
|
6
8
|
value === undefined || value === '' || Number.isNaN( Number( value ) );
|
|
7
9
|
|
|
8
|
-
export const NumberControl = ( { placeholder }: { placeholder?: string } ) => {
|
|
10
|
+
export const NumberControl = createControl( ( { placeholder }: { placeholder?: string } ) => {
|
|
9
11
|
const { value, setValue } = useControl< number | undefined >();
|
|
10
12
|
|
|
11
13
|
const handleChange = ( event: React.ChangeEvent< HTMLInputElement > ) => {
|
|
@@ -14,12 +16,14 @@ export const NumberControl = ( { placeholder }: { placeholder?: string } ) => {
|
|
|
14
16
|
};
|
|
15
17
|
|
|
16
18
|
return (
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
<ControlActions>
|
|
20
|
+
<TextField
|
|
21
|
+
size="tiny"
|
|
22
|
+
type="number"
|
|
23
|
+
value={ isEmptyOrNaN( value ) ? '' : value }
|
|
24
|
+
onChange={ handleChange }
|
|
25
|
+
placeholder={ placeholder }
|
|
26
|
+
/>
|
|
27
|
+
</ControlActions>
|
|
24
28
|
);
|
|
25
|
-
};
|
|
29
|
+
} );
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { MenuItem, Select, SelectChangeEvent } from '@elementor/ui';
|
|
3
3
|
import { useControl } from '../control-context';
|
|
4
|
-
import { PropValue } from '
|
|
4
|
+
import { PropValue } from '../props/types';
|
|
5
|
+
import ControlActions from '../control-actions/control-actions';
|
|
6
|
+
import { createControl } from '../create-control';
|
|
5
7
|
|
|
6
8
|
type Props< T > = {
|
|
7
9
|
options: Array< { label: string; value: T; disabled?: boolean } >;
|
|
8
10
|
};
|
|
9
11
|
|
|
10
|
-
export const SelectControl = < T extends PropValue >( { options }: Props< T > ) => {
|
|
12
|
+
export const SelectControl = createControl( < T extends PropValue >( { options }: Props< T > ) => {
|
|
11
13
|
const { value, setValue } = useControl< T >();
|
|
12
14
|
|
|
13
15
|
const handleChange = ( event: SelectChangeEvent< T > ) => {
|
|
@@ -15,12 +17,14 @@ export const SelectControl = < T extends PropValue >( { options }: Props< T > )
|
|
|
15
17
|
};
|
|
16
18
|
|
|
17
19
|
return (
|
|
18
|
-
<
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
{
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
<ControlActions>
|
|
21
|
+
<Select size="tiny" value={ value ?? '' } onChange={ handleChange }>
|
|
22
|
+
{ options.map( ( { label, ...props } ) => (
|
|
23
|
+
<MenuItem key={ props.value } { ...props }>
|
|
24
|
+
{ label }
|
|
25
|
+
</MenuItem>
|
|
26
|
+
) ) }
|
|
27
|
+
</Select>
|
|
28
|
+
</ControlActions>
|
|
25
29
|
);
|
|
26
|
-
};
|
|
30
|
+
} );
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { InputAdornment } from '@elementor/ui';
|
|
3
|
-
import { TransformablePropValue } from '
|
|
3
|
+
import { TransformablePropValue } from '../props/types';
|
|
4
4
|
import { useControl } from '../control-context';
|
|
5
5
|
import { useSyncExternalState } from '../hooks/use-sync-external-state';
|
|
6
6
|
import { SelectionEndAdornment, TextFieldInnerSelection } from '../components/text-field-inner-selection';
|
|
7
|
+
import ControlActions from '../control-actions/control-actions';
|
|
8
|
+
import { createControl } from '../create-control';
|
|
7
9
|
|
|
8
10
|
export type Unit = 'px' | '%' | 'em' | 'rem' | 'vw';
|
|
9
11
|
|
|
10
12
|
const defaultUnits: Unit[] = [ 'px', '%', 'em', 'rem', 'vw' ];
|
|
11
13
|
|
|
12
|
-
export type SizeControlValue = TransformablePropValue< { unit: Unit; size: number } >;
|
|
14
|
+
export type SizeControlValue = TransformablePropValue< 'size', { unit: Unit; size: number } >;
|
|
13
15
|
|
|
14
16
|
export type SizeControlProps = {
|
|
15
17
|
placeholder?: string;
|
|
@@ -17,7 +19,7 @@ export type SizeControlProps = {
|
|
|
17
19
|
units?: Unit[];
|
|
18
20
|
};
|
|
19
21
|
|
|
20
|
-
export const SizeControl = ( { units = defaultUnits, placeholder, startIcon }: SizeControlProps ) => {
|
|
22
|
+
export const SizeControl = createControl( ( { units = defaultUnits, placeholder, startIcon }: SizeControlProps ) => {
|
|
21
23
|
const { value, setValue } = useControl< SizeControlValue >();
|
|
22
24
|
|
|
23
25
|
const [ state, setState ] = useSyncExternalState< SizeControlValue >( {
|
|
@@ -53,15 +55,17 @@ export const SizeControl = ( { units = defaultUnits, placeholder, startIcon }: S
|
|
|
53
55
|
};
|
|
54
56
|
|
|
55
57
|
return (
|
|
56
|
-
<
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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>
|
|
66
70
|
);
|
|
67
|
-
};
|
|
71
|
+
} );
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { TextField } from '@elementor/ui';
|
|
3
3
|
import { useControl } from '../control-context';
|
|
4
|
+
import ControlActions from '../control-actions/control-actions';
|
|
5
|
+
import { createControl } from '../create-control';
|
|
4
6
|
|
|
5
7
|
type Props = {
|
|
6
8
|
placeholder?: string;
|
|
7
9
|
};
|
|
8
10
|
|
|
9
|
-
export const TextAreaControl = ( { placeholder }: Props ) => {
|
|
11
|
+
export const TextAreaControl = createControl( ( { placeholder }: Props ) => {
|
|
10
12
|
const { value, setValue } = useControl< string >();
|
|
11
13
|
|
|
12
14
|
const handleChange = ( event: React.ChangeEvent< HTMLInputElement > ) => {
|
|
@@ -14,14 +16,16 @@ export const TextAreaControl = ( { placeholder }: Props ) => {
|
|
|
14
16
|
};
|
|
15
17
|
|
|
16
18
|
return (
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
<ControlActions fullWidth>
|
|
20
|
+
<TextField
|
|
21
|
+
size="tiny"
|
|
22
|
+
multiline
|
|
23
|
+
fullWidth
|
|
24
|
+
rows={ 5 }
|
|
25
|
+
value={ value }
|
|
26
|
+
onChange={ handleChange }
|
|
27
|
+
placeholder={ placeholder }
|
|
28
|
+
/>
|
|
29
|
+
</ControlActions>
|
|
26
30
|
);
|
|
27
|
-
};
|
|
31
|
+
} );
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { TextField } from '@elementor/ui';
|
|
3
3
|
import { useControl } from '../control-context';
|
|
4
|
+
import ControlActions from '../control-actions/control-actions';
|
|
5
|
+
import { createControl } from '../create-control';
|
|
4
6
|
|
|
5
|
-
export const TextControl = ( { placeholder }: { placeholder?: string } ) => {
|
|
7
|
+
export const TextControl = createControl( ( { placeholder }: { placeholder?: string } ) => {
|
|
6
8
|
const { value, setValue } = useControl< string >( '' );
|
|
7
9
|
|
|
8
10
|
const handleChange = ( event: React.ChangeEvent< HTMLInputElement > ) => setValue( event.target.value );
|
|
9
11
|
|
|
10
|
-
return
|
|
11
|
-
|
|
12
|
+
return (
|
|
13
|
+
<ControlActions fullWidth>
|
|
14
|
+
<TextField type="text" size="tiny" value={ value } onChange={ handleChange } placeholder={ placeholder } />
|
|
15
|
+
</ControlActions>
|
|
16
|
+
);
|
|
17
|
+
} );
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { useControl } from '../control-context';
|
|
3
3
|
import { ControlToggleButtonGroup, ToggleButtonGroupItem } from '../components/control-toggle-button-group';
|
|
4
|
-
import { PropValue } from '
|
|
4
|
+
import { PropValue } from '../props/types';
|
|
5
|
+
import { createControl } from '../create-control';
|
|
5
6
|
|
|
6
7
|
type ToggleControlProps< T extends PropValue > = {
|
|
7
8
|
options: ToggleButtonGroupItem< T >[];
|
|
8
9
|
};
|
|
9
10
|
|
|
10
|
-
export const ToggleControl = < T extends PropValue >( { options }: ToggleControlProps< T > ) => {
|
|
11
|
+
export const ToggleControl = createControl( < T extends PropValue >( { options }: ToggleControlProps< T > ) => {
|
|
11
12
|
const { value, setValue } = useControl< T >();
|
|
12
13
|
|
|
13
14
|
const handleToggle = ( option: T | null ) => {
|
|
@@ -22,4 +23,4 @@ export const ToggleControl = < T extends PropValue >( { options }: ToggleControl
|
|
|
22
23
|
exclusive={ true }
|
|
23
24
|
/>
|
|
24
25
|
);
|
|
25
|
-
};
|
|
26
|
+
} );
|
package/src/controls/control.tsx
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { ComponentProps } from 'react';
|
|
3
|
-
import { getControlReplacement } from './control-replacement';
|
|
4
|
-
import { useControl } from './control-context';
|
|
5
3
|
import { createError } from '@elementor/utils';
|
|
6
4
|
import { ControlType, ControlTypes, getControlByType } from './controls-registry';
|
|
7
5
|
|
|
@@ -33,8 +31,6 @@ type ControlProps< T extends ControlType > = AnyPropertyRequired< ComponentProps
|
|
|
33
31
|
};
|
|
34
32
|
|
|
35
33
|
export const Control = < T extends ControlType >( { props, type }: ControlProps< T > ) => {
|
|
36
|
-
const { value } = useControl();
|
|
37
|
-
|
|
38
34
|
const ControlByType = getControlByType( type );
|
|
39
35
|
|
|
40
36
|
if ( ! ControlByType ) {
|
|
@@ -43,8 +39,6 @@ export const Control = < T extends ControlType >( { props, type }: ControlProps<
|
|
|
43
39
|
} );
|
|
44
40
|
}
|
|
45
41
|
|
|
46
|
-
const ControlComponent = getControlReplacement( { value } ) || ControlByType;
|
|
47
|
-
|
|
48
42
|
// @ts-expect-error ControlComponent props are inferred from the type (T).
|
|
49
|
-
return <
|
|
43
|
+
return <ControlByType { ...props } />;
|
|
50
44
|
};
|