@elementor/editor-controls 4.4.0-1123 → 4.4.0-1125

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": "4.4.0-1123",
4
+ "version": "4.4.0-1125",
5
5
  "private": false,
6
6
  "author": "Elementor Team",
7
7
  "homepage": "https://elementor.com/",
@@ -40,23 +40,23 @@
40
40
  "dev": "tsup --config=../../tsup.dev.ts"
41
41
  },
42
42
  "dependencies": {
43
- "@elementor/editor-current-user": "4.4.0-1123",
44
- "@elementor/editor-elements": "4.4.0-1123",
45
- "@elementor/editor-props": "4.4.0-1123",
46
- "@elementor/editor-responsive": "4.4.0-1123",
47
- "@elementor/editor-ui": "4.4.0-1123",
48
- "@elementor/editor-v1-adapters": "4.4.0-1123",
49
- "@elementor/env": "4.4.0-1123",
50
- "@elementor/events": "4.4.0-1123",
51
- "@elementor/http-client": "4.4.0-1123",
43
+ "@elementor/editor-current-user": "4.4.0-1125",
44
+ "@elementor/editor-elements": "4.4.0-1125",
45
+ "@elementor/editor-props": "4.4.0-1125",
46
+ "@elementor/editor-responsive": "4.4.0-1125",
47
+ "@elementor/editor-ui": "4.4.0-1125",
48
+ "@elementor/editor-v1-adapters": "4.4.0-1125",
49
+ "@elementor/env": "4.4.0-1125",
50
+ "@elementor/events": "4.4.0-1125",
51
+ "@elementor/http-client": "4.4.0-1125",
52
52
  "@elementor/icons": "~1.75.1",
53
- "@elementor/locations": "4.4.0-1123",
54
- "@elementor/query": "4.4.0-1123",
55
- "@elementor/schema": "4.4.0-1123",
56
- "@elementor/session": "4.4.0-1123",
53
+ "@elementor/locations": "4.4.0-1125",
54
+ "@elementor/query": "4.4.0-1125",
55
+ "@elementor/schema": "4.4.0-1125",
56
+ "@elementor/session": "4.4.0-1125",
57
57
  "@elementor/ui": "1.37.5",
58
- "@elementor/utils": "4.4.0-1123",
59
- "@elementor/wp-media": "4.4.0-1123",
58
+ "@elementor/utils": "4.4.0-1125",
59
+ "@elementor/wp-media": "4.4.0-1125",
60
60
  "@monaco-editor/react": "^4.7.0",
61
61
  "@tanstack/react-virtual": "^3.13.3",
62
62
  "@tiptap/extension-bold": "^3.11.1",
@@ -24,7 +24,7 @@ export const ImageControl = createControl( ( { sizes, label = __( 'Image', 'elem
24
24
  <PropProvider { ...propContext }>
25
25
  <Stack gap={ 1.5 }>
26
26
  <ControlLabel>{ label }</ControlLabel>
27
- <ImageSrcControl />
27
+ <ImageSrcControl label={ label } />
28
28
  <Grid container gap={ 1.5 } alignItems="center" flexWrap="nowrap">
29
29
  <Grid item xs={ 6 }>
30
30
  <ControlFormLabel>{ __( 'Resolution', 'elementor' ) }</ControlFormLabel>
@@ -38,13 +38,13 @@ export const ImageControl = createControl( ( { sizes, label = __( 'Image', 'elem
38
38
  );
39
39
  } );
40
40
 
41
- const ImageSrcControl = () => {
41
+ const ImageSrcControl = ( { label }: { label: string } ) => {
42
42
  const { data: allowSvgUpload } = useUnfilteredFilesUpload();
43
43
  const mediaTypes: MediaType[] = allowSvgUpload ? [ 'image', 'svg' ] : [ 'image' ];
44
44
 
45
45
  return (
46
46
  <PropKeyProvider bind={ 'src' }>
47
- <ImageMediaControl mediaTypes={ mediaTypes } />
47
+ <ImageMediaControl mediaTypes={ mediaTypes } label={ label } />
48
48
  </PropKeyProvider>
49
49
  );
50
50
  };
@@ -1,19 +1,22 @@
1
1
  import * as React from 'react';
2
2
  import { imageSrcPropTypeUtil, stringPropTypeUtil, urlPropTypeUtil } from '@elementor/editor-props';
3
- import { UploadIcon } from '@elementor/icons';
4
- import { Button, Card, CardMedia, CardOverlay, CircularProgress, Stack } from '@elementor/ui';
3
+ import { Card, CardMedia, CardOverlay, CircularProgress, Stack } from '@elementor/ui';
5
4
  import { type MediaType, useWpMediaAttachment, useWpMediaFrame } from '@elementor/wp-media';
6
5
  import { __ } from '@wordpress/i18n';
7
6
 
8
7
  import { useBoundProp } from '../bound-prop-context';
9
8
  import ControlActions from '../control-actions/control-actions';
10
9
  import { createControl } from '../create-control';
10
+ import { MediaSelectActions } from './media-select-actions';
11
11
 
12
12
  type ImageMediaControlProps = {
13
13
  mediaTypes?: MediaType[];
14
+ label?: string;
14
15
  };
15
16
 
16
- export const ImageMediaControl = createControl( ( { mediaTypes = [ 'image' ] }: ImageMediaControlProps ) => {
17
+ export const ImageMediaControl = createControl( ( { mediaTypes, label }: ImageMediaControlProps ) => {
18
+ const resolvedMediaTypes = mediaTypes ?? [ 'image' ];
19
+ const groupLabel = label ?? __( 'Image', 'elementor' );
17
20
  const { value, setValue, propType, placeholder } = useBoundProp( imageSrcPropTypeUtil );
18
21
  const { id, url } = value ?? {};
19
22
 
@@ -26,7 +29,7 @@ export const ImageMediaControl = createControl( ( { mediaTypes = [ 'image' ] }:
26
29
  const currentAltForModal = ( value as { alt?: { value?: string } | null } | null | undefined )?.alt?.value;
27
30
 
28
31
  const { open } = useWpMediaFrame( {
29
- mediaTypes,
32
+ mediaTypes: resolvedMediaTypes,
30
33
  multiple: false,
31
34
  selected: id?.value || null,
32
35
  allowUrlImport: true,
@@ -61,35 +64,14 @@ export const ImageMediaControl = createControl( ( { mediaTypes = [ 'image' ] }:
61
64
  ) }
62
65
  </CardMedia>
63
66
  <CardOverlay>
64
- <Stack gap={ 1 }>
65
- <Button
66
- size="tiny"
67
- color="inherit"
68
- variant="outlined"
69
- onClick={ () => open( { mode: 'browse' } ) }
70
- >
71
- { __( 'Select image', 'elementor' ) }
72
- </Button>
73
- <Button
74
- size="tiny"
75
- variant="text"
76
- color="inherit"
77
- startIcon={ <UploadIcon /> }
78
- onClick={ () => open( { mode: 'upload' } ) }
79
- >
80
- { __( 'Upload', 'elementor' ) }
81
- </Button>
82
- <Button
83
- size="tiny"
84
- variant="text"
85
- color="inherit"
86
- onClick={ () =>
87
- open( { mode: 'url', currentUrl: currentUrlForModal, currentAlt: currentAltForModal } )
88
- }
89
- >
90
- { __( 'Insert from URL', 'elementor' ) }
91
- </Button>
92
- </Stack>
67
+ <MediaSelectActions
68
+ label={ groupLabel }
69
+ onSelect={ () => open( { mode: 'browse' } ) }
70
+ onUpload={ () => open( { mode: 'upload' } ) }
71
+ onInsertUrl={ () =>
72
+ open( { mode: 'url', currentUrl: currentUrlForModal, currentAlt: currentAltForModal } )
73
+ }
74
+ />
93
75
  </CardOverlay>
94
76
  </Card>
95
77
  </ControlActions>
@@ -0,0 +1,105 @@
1
+ import * as React from 'react';
2
+ import { UploadIcon } from '@elementor/icons';
3
+ import { Box, Button, Stack, styled } from '@elementor/ui';
4
+ import { __ } from '@wordpress/i18n';
5
+
6
+ const SELECT_AREA_WIDTH = 72;
7
+ const UPLOAD_AREA_WIDTH = 48;
8
+ const SPLIT_BUTTON_MIN_HEIGHT = 32;
9
+ const SPLIT_BUTTON_CORNER_RADIUS = '8px';
10
+ const SPLIT_BUTTON_FONT_SIZE = '14px';
11
+
12
+ const actionButtonSx = {
13
+ minWidth: 0,
14
+ minHeight: SPLIT_BUTTON_MIN_HEIGHT,
15
+ px: 2,
16
+ fontSize: SPLIT_BUTTON_FONT_SIZE,
17
+ fontWeight: 500,
18
+ lineHeight: 1,
19
+ };
20
+
21
+ const SplitButtonGroup = styled( Stack )( {
22
+ display: 'inline-flex',
23
+ flexDirection: 'row',
24
+ alignItems: 'stretch',
25
+ border: '1px solid currentColor',
26
+ borderRadius: SPLIT_BUTTON_CORNER_RADIUS,
27
+ overflow: 'hidden',
28
+ '& .MuiButton-root': {
29
+ border: 'none',
30
+ borderRadius: 0,
31
+ lineHeight: 1,
32
+ },
33
+ } );
34
+
35
+ type MediaActionGroupProps = {
36
+ label: string;
37
+ onSelect: () => void;
38
+ uploadSlot: React.ReactNode;
39
+ groupRef?: React.Ref< HTMLDivElement >;
40
+ testId?: string;
41
+ };
42
+
43
+ export const MediaActionGroup = ( { label, onSelect, uploadSlot, groupRef, testId }: MediaActionGroupProps ) => (
44
+ <SplitButtonGroup ref={ groupRef } role="group" aria-label={ label } direction="row" data-testid={ testId }>
45
+ <Button
46
+ size="tiny"
47
+ color="inherit"
48
+ variant="text"
49
+ onClick={ onSelect }
50
+ sx={ { ...actionButtonSx, minWidth: SELECT_AREA_WIDTH } }
51
+ >
52
+ { __( 'Select', 'elementor' ) }
53
+ </Button>
54
+ <Box
55
+ sx={ {
56
+ width: '1px',
57
+ alignSelf: 'stretch',
58
+ bgcolor: 'currentColor',
59
+ flexShrink: 0,
60
+ } }
61
+ />
62
+ <Box component="span" sx={ { display: 'flex', width: UPLOAD_AREA_WIDTH } }>
63
+ { uploadSlot }
64
+ </Box>
65
+ </SplitButtonGroup>
66
+ );
67
+
68
+ type MediaUploadButtonProps = {
69
+ disabled?: boolean;
70
+ onClick?: () => void;
71
+ };
72
+
73
+ export const MediaUploadButton = ( { disabled = false, onClick }: MediaUploadButtonProps ) => (
74
+ <Button
75
+ sx={ { ...actionButtonSx, width: '100%' } }
76
+ size="tiny"
77
+ color="inherit"
78
+ variant="text"
79
+ disabled={ disabled }
80
+ onClick={ onClick }
81
+ aria-label={ __( 'Upload', 'elementor' ) }
82
+ >
83
+ <UploadIcon fontSize="small" />
84
+ </Button>
85
+ );
86
+
87
+ type MediaSelectActionsProps = {
88
+ label: string;
89
+ onSelect: () => void;
90
+ onUpload: () => void;
91
+ onInsertUrl: () => void;
92
+ };
93
+
94
+ export const MediaSelectActions = ( { label, onSelect, onUpload, onInsertUrl }: MediaSelectActionsProps ) => (
95
+ <Stack alignItems="center" gap={ 1 }>
96
+ <MediaActionGroup
97
+ label={ label }
98
+ onSelect={ onSelect }
99
+ uploadSlot={ <MediaUploadButton onClick={ onUpload } /> }
100
+ />
101
+ <Button size="tiny" variant="text" color="inherit" onClick={ onInsertUrl }>
102
+ { __( 'Insert URL', 'elementor' ) }
103
+ </Button>
104
+ </Stack>
105
+ );
@@ -51,9 +51,11 @@ const MODE_UPLOAD: OpenOptions = { mode: 'upload' };
51
51
 
52
52
  type SvgMediaControlProps = {
53
53
  showIconLibrary?: boolean;
54
+ label?: string;
54
55
  };
55
56
 
56
- export const SvgMediaControl = createControl( ( { showIconLibrary = false }: SvgMediaControlProps ) => {
57
+ export const SvgMediaControl = createControl( ( { showIconLibrary = false, label }: SvgMediaControlProps ) => {
58
+ const groupLabel = label ?? __( 'SVG', 'elementor' );
57
59
  const { value: svgValue, setValue: setSvgValue } = useBoundProp( svgSrcPropTypeUtil );
58
60
  const { value: iconValue, setValue: setIconValue } = useBoundProp( iconPropTypeUtil );
59
61
  const id = svgValue?.id;
@@ -208,6 +210,7 @@ export const SvgMediaControl = createControl( ( { showIconLibrary = false }: Svg
208
210
  } }
209
211
  >
210
212
  <SvgMediaOverlay
213
+ label={ groupLabel }
211
214
  isAdmin={ isAdmin }
212
215
  showIconLibrary={ showIconLibrary }
213
216
  buttonGroupRef={ buttonGroupRef }
@@ -1,44 +1,18 @@
1
1
  import * as React from 'react';
2
- import { LibraryIcon, UploadIcon } from '@elementor/icons';
3
- import { Box, Button, Stack, styled, type SxProps, ThemeProvider, Typography } from '@elementor/ui';
2
+ import { LibraryIcon } from '@elementor/icons';
3
+ import { Box, Button, Stack, ThemeProvider, Typography } from '@elementor/ui';
4
4
  import { __ } from '@wordpress/i18n';
5
5
 
6
6
  import { ConditionalControlInfotip } from '../components/conditional-control-infotip';
7
+ import { MediaActionGroup, MediaUploadButton } from './media-select-actions';
7
8
 
8
9
  export const SVG_MEDIA_CONTROL_CONTAINER_TEST_ID = 'svg-media-control-container';
9
10
  export const SVG_MEDIA_ACTION_GROUP_TEST_ID = 'svg-media-action-group';
10
11
 
11
- const SELECT_AREA_WIDTH = 72;
12
- const UPLOAD_AREA_WIDTH = 48;
13
- const SPLIT_BUTTON_MIN_HEIGHT = 32;
14
- const SPLIT_BUTTON_CORNER_RADIUS = '8px';
15
- const SPLIT_BUTTON_FONT_SIZE = '14px';
16
12
  const ICON_LIBRARY_PADDING = 0.625;
17
13
 
18
- const svgButtonSx = {
19
- minWidth: 0,
20
- minHeight: SPLIT_BUTTON_MIN_HEIGHT,
21
- px: 2,
22
- fontSize: SPLIT_BUTTON_FONT_SIZE,
23
- fontWeight: 500,
24
- lineHeight: 1,
25
- };
26
-
27
- const MediaActionGroup = styled( Stack )( {
28
- display: 'inline-flex',
29
- flexDirection: 'row',
30
- alignItems: 'stretch',
31
- border: '1px solid currentColor',
32
- borderRadius: SPLIT_BUTTON_CORNER_RADIUS,
33
- overflow: 'hidden',
34
- '& .MuiButton-root': {
35
- border: 'none',
36
- borderRadius: 0,
37
- lineHeight: 1,
38
- },
39
- } );
40
-
41
14
  type SvgMediaOverlayProps = {
15
+ label: string;
42
16
  isAdmin: boolean;
43
17
  showIconLibrary: boolean;
44
18
  buttonGroupRef: React.Ref< HTMLDivElement >;
@@ -50,6 +24,7 @@ type SvgMediaOverlayProps = {
50
24
  };
51
25
 
52
26
  export const SvgMediaOverlay = ( {
27
+ label,
53
28
  isAdmin,
54
29
  showIconLibrary,
55
30
  buttonGroupRef,
@@ -60,35 +35,23 @@ export const SvgMediaOverlay = ( {
60
35
  infotipDescription,
61
36
  }: SvgMediaOverlayProps ) => (
62
37
  <Stack alignItems="center" gap={ 1 }>
63
- <MediaActionGroup ref={ buttonGroupRef } direction="row" data-testid={ SVG_MEDIA_ACTION_GROUP_TEST_ID }>
64
- <Button
65
- size="tiny"
66
- color="inherit"
67
- variant="text"
68
- onClick={ onSelectSvg }
69
- aria-label={ __( 'Select', 'elementor' ) }
70
- sx={ { ...svgButtonSx, minWidth: SELECT_AREA_WIDTH } }
71
- >
72
- { __( 'Select', 'elementor' ) }
73
- </Button>
74
- <Box
75
- sx={ {
76
- width: '1px',
77
- alignSelf: 'stretch',
78
- bgcolor: 'currentColor',
79
- flexShrink: 0,
80
- } }
81
- />
82
- <ConditionalControlInfotip
83
- title={ infotipTitle }
84
- description={ infotipDescription }
85
- isEnabled={ ! isAdmin }
86
- >
87
- <Box component="span" sx={ { display: 'flex', width: UPLOAD_AREA_WIDTH } }>
88
- <UploadControl isAdmin={ isAdmin } onUpload={ onUpload } />
89
- </Box>
90
- </ConditionalControlInfotip>
91
- </MediaActionGroup>
38
+ <MediaActionGroup
39
+ label={ label }
40
+ onSelect={ onSelectSvg }
41
+ groupRef={ buttonGroupRef }
42
+ testId={ SVG_MEDIA_ACTION_GROUP_TEST_ID }
43
+ uploadSlot={
44
+ <ConditionalControlInfotip
45
+ title={ infotipTitle }
46
+ description={ infotipDescription }
47
+ isEnabled={ ! isAdmin }
48
+ >
49
+ <Box component="span" sx={ { display: 'flex', width: '100%' } }>
50
+ <UploadControl isAdmin={ isAdmin } onUpload={ onUpload } />
51
+ </Box>
52
+ </ConditionalControlInfotip>
53
+ }
54
+ />
92
55
  { showIconLibrary ? (
93
56
  <Button
94
57
  size="tiny"
@@ -111,34 +74,12 @@ export const SvgMediaOverlay = ( {
111
74
 
112
75
  const UploadControl = ( { isAdmin, onUpload }: { isAdmin: boolean; onUpload: () => void } ) => {
113
76
  if ( isAdmin ) {
114
- return <UploadButton sx={ svgButtonSx } onClick={ onUpload } />;
77
+ return <MediaUploadButton onClick={ onUpload } />;
115
78
  }
116
79
 
117
80
  return (
118
81
  <ThemeProvider colorScheme="dark">
119
- <UploadButton disabled sx={ svgButtonSx } />
82
+ <MediaUploadButton disabled />
120
83
  </ThemeProvider>
121
84
  );
122
85
  };
123
-
124
- const UploadButton = ( {
125
- disabled = false,
126
- sx,
127
- onClick,
128
- }: {
129
- disabled?: boolean;
130
- sx?: SxProps;
131
- onClick?: () => void;
132
- } ) => (
133
- <Button
134
- sx={ { ...sx, width: '100%' } }
135
- size="tiny"
136
- color="inherit"
137
- variant="text"
138
- disabled={ disabled }
139
- onClick={ onClick }
140
- aria-label={ __( 'Upload', 'elementor' ) }
141
- >
142
- <UploadIcon fontSize="small" />
143
- </Button>
144
- );
@@ -1,18 +1,22 @@
1
1
  import * as React from 'react';
2
2
  import { urlPropTypeUtil, videoSrcPropTypeUtil } from '@elementor/editor-props';
3
- import { UploadIcon } from '@elementor/icons';
4
- import { Button, Card, CardMedia, CardOverlay, CircularProgress, Stack } from '@elementor/ui';
3
+ import { Card, CardMedia, CardOverlay, CircularProgress } from '@elementor/ui';
5
4
  import { useWpMediaAttachment, useWpMediaFrame } from '@elementor/wp-media';
6
5
  import { __ } from '@wordpress/i18n';
7
6
 
8
7
  import { useBoundProp } from '../bound-prop-context';
9
8
  import ControlActions from '../control-actions/control-actions';
10
9
  import { createControl } from '../create-control';
10
+ import { MediaSelectActions } from './media-select-actions';
11
11
  import { TILES_GRADIENT_FORMULA } from './svg-media-control';
12
12
 
13
13
  const PLACEHOLDER_IMAGE = window.elementorCommon?.config?.urls?.assets + '/shapes/play-triangle.svg';
14
14
 
15
- export const VideoMediaControl = createControl( () => {
15
+ type VideoMediaControlProps = {
16
+ label?: string;
17
+ };
18
+
19
+ export const VideoMediaControl = createControl( ( { label = __( 'Video', 'elementor' ) }: VideoMediaControlProps ) => {
16
20
  const { value, setValue, propType } = useBoundProp( videoSrcPropTypeUtil );
17
21
  const { id, url } = value ?? {};
18
22
 
@@ -63,33 +67,12 @@ export const VideoMediaControl = createControl( () => {
63
67
  <VideoPreview isFetching={ isFetching } videoUrl={ videoUrl } />
64
68
  </CardMedia>
65
69
  <CardOverlay>
66
- <Stack gap={ 1 }>
67
- <Button
68
- size="tiny"
69
- color="inherit"
70
- variant="outlined"
71
- onClick={ () => open( { mode: 'browse' } ) }
72
- >
73
- { __( 'Select video', 'elementor' ) }
74
- </Button>
75
- <Button
76
- size="tiny"
77
- variant="text"
78
- color="inherit"
79
- startIcon={ <UploadIcon /> }
80
- onClick={ () => open( { mode: 'upload' } ) }
81
- >
82
- { __( 'Upload', 'elementor' ) }
83
- </Button>
84
- <Button
85
- size="tiny"
86
- variant="text"
87
- color="inherit"
88
- onClick={ () => open( { mode: 'url', currentUrl: currentUrlForModal } ) }
89
- >
90
- { __( 'Insert from URL', 'elementor' ) }
91
- </Button>
92
- </Stack>
70
+ <MediaSelectActions
71
+ label={ label }
72
+ onSelect={ () => open( { mode: 'browse' } ) }
73
+ onUpload={ () => open( { mode: 'upload' } ) }
74
+ onInsertUrl={ () => open( { mode: 'url', currentUrl: currentUrlForModal } ) }
75
+ />
93
76
  </CardOverlay>
94
77
  </Card>
95
78
  </ControlActions>