@elementor/editor-controls 0.26.0 → 0.28.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.26.0",
4
+ "version": "0.28.0",
5
5
  "private": false,
6
6
  "author": "Elementor Team",
7
7
  "homepage": "https://elementor.com/",
@@ -43,13 +43,13 @@
43
43
  "@elementor/editor-current-user": "0.3.0",
44
44
  "@elementor/editor-elements": "0.8.1",
45
45
  "@elementor/editor-props": "0.12.0",
46
- "@elementor/editor-ui": "0.7.1",
46
+ "@elementor/editor-ui": "0.8.1",
47
47
  "@elementor/env": "0.3.5",
48
48
  "@elementor/http": "0.1.4",
49
- "@elementor/icons": "1.37.0",
49
+ "@elementor/icons": "1.40.1",
50
50
  "@elementor/query": "0.2.4",
51
51
  "@elementor/session": "0.1.0",
52
- "@elementor/ui": "1.32.1",
52
+ "@elementor/ui": "1.34.2",
53
53
  "@elementor/utils": "0.4.0",
54
54
  "@elementor/wp-media": "0.6.0",
55
55
  "@tanstack/react-virtual": "3.13.3",
@@ -0,0 +1,49 @@
1
+ import * as React from 'react';
2
+ import { type ComponentType, createContext, type PropsWithChildren, useContext } from 'react';
3
+ import { type PropValue } from '@elementor/editor-props';
4
+
5
+ import { useBoundProp } from './bound-prop-context';
6
+
7
+ type ControlReplacement = {
8
+ component: ComponentType;
9
+ condition: ( { value }: ConditionArgs ) => boolean;
10
+ };
11
+
12
+ type ConditionArgs = {
13
+ value: PropValue;
14
+ };
15
+
16
+ type Props = PropsWithChildren< { replacements: ControlReplacement[] } >;
17
+
18
+ const ControlReplacementContext = createContext< ControlReplacement[] >( [] );
19
+
20
+ export const ControlReplacementsProvider = ( { replacements, children }: Props ) => {
21
+ return <ControlReplacementContext.Provider value={ replacements }>{ children }</ControlReplacementContext.Provider>;
22
+ };
23
+
24
+ export const useControlReplacement = ( OriginalComponent: ComponentType ) => {
25
+ const { value } = useBoundProp();
26
+ const replacements = useContext( ControlReplacementContext );
27
+
28
+ try {
29
+ const replacement = replacements.find( ( r ) => r.condition( { value } ) );
30
+
31
+ return replacement?.component ?? OriginalComponent;
32
+ } catch {
33
+ return OriginalComponent;
34
+ }
35
+ };
36
+
37
+ export const createControlReplacementsRegistry = () => {
38
+ const controlReplacements: ControlReplacement[] = [];
39
+
40
+ function registerControlReplacement( replacement: ControlReplacement ) {
41
+ controlReplacements.push( replacement );
42
+ }
43
+
44
+ function getControlReplacements() {
45
+ return controlReplacements;
46
+ }
47
+
48
+ return { registerControlReplacement, getControlReplacements };
49
+ };
@@ -135,7 +135,6 @@ export function EqualUnequalSizesControl< TMultiPropType extends string, TPropVa
135
135
  } }
136
136
  { ...bindPopover( popupState ) }
137
137
  slotProps={ {
138
- // eslint-disable-next-line react-compiler/react-compiler
139
138
  paper: { sx: { mt: 0.5, width: controlRef.current?.getBoundingClientRect().width } },
140
139
  } }
141
140
  >
@@ -14,10 +14,11 @@ import { SelectControl } from './select-control';
14
14
  type ImageControlProps = {
15
15
  sizes: { label: string; value: string }[];
16
16
  resolutionLabel?: string;
17
+ showMode?: 'all' | 'media' | 'sizes';
17
18
  };
18
19
 
19
20
  export const ImageControl = createControl(
20
- ( { sizes, resolutionLabel = __( 'Image resolution', 'elementor' ) }: ImageControlProps ) => {
21
+ ( { sizes, resolutionLabel = __( 'Image resolution', 'elementor' ), showMode = 'all' }: ImageControlProps ) => {
21
22
  const propContext = useBoundProp( imagePropTypeUtil );
22
23
 
23
24
  const { data: allowSvgUpload } = useUnfilteredFilesUpload();
@@ -26,20 +27,24 @@ export const ImageControl = createControl(
26
27
  return (
27
28
  <PropProvider { ...propContext }>
28
29
  <Stack gap={ 1.5 }>
29
- <PropKeyProvider bind={ 'src' }>
30
- <ControlFormLabel> { __( 'Image', 'elementor' ) } </ControlFormLabel>
31
- <ImageMediaControl mediaTypes={ mediaTypes } />
32
- </PropKeyProvider>
33
- <PropKeyProvider bind={ 'size' }>
34
- <Grid container gap={ 1.5 } alignItems="center" flexWrap="nowrap">
35
- <Grid item xs={ 6 }>
36
- <ControlFormLabel> { resolutionLabel } </ControlFormLabel>
30
+ { [ 'all', 'media' ].includes( showMode ) ? (
31
+ <PropKeyProvider bind={ 'src' }>
32
+ <ControlFormLabel> { __( 'Image', 'elementor' ) } </ControlFormLabel>
33
+ <ImageMediaControl mediaTypes={ mediaTypes } />
34
+ </PropKeyProvider>
35
+ ) : null }
36
+ { [ 'all', 'sizes' ].includes( showMode ) ? (
37
+ <PropKeyProvider bind={ 'size' }>
38
+ <Grid container gap={ 1.5 } alignItems="center" flexWrap="nowrap">
39
+ <Grid item xs={ 6 }>
40
+ <ControlFormLabel> { resolutionLabel } </ControlFormLabel>
41
+ </Grid>
42
+ <Grid item xs={ 6 } sx={ { overflow: 'hidden' } }>
43
+ <SelectControl options={ sizes } />
44
+ </Grid>
37
45
  </Grid>
38
- <Grid item xs={ 6 } sx={ { overflow: 'hidden' } }>
39
- <SelectControl options={ sizes } />
40
- </Grid>
41
- </Grid>
42
- </PropKeyProvider>
46
+ </PropKeyProvider>
47
+ ) : null }
43
48
  </Stack>
44
49
  </PropProvider>
45
50
  );
@@ -13,7 +13,7 @@ import { InfoTipCard } from '@elementor/editor-ui';
13
13
  import { type HttpResponse, httpService } from '@elementor/http';
14
14
  import { AlertTriangleIcon, MinusIcon, PlusIcon } from '@elementor/icons';
15
15
  import { useSessionStorage } from '@elementor/session';
16
- import { Box, Collapse, Divider, Grid, IconButton, Infotip, Stack, Switch } from '@elementor/ui';
16
+ import { Box, Collapse, Grid, IconButton, Infotip, Stack, Switch } from '@elementor/ui';
17
17
  import { debounce } from '@elementor/utils';
18
18
  import { __ } from '@wordpress/i18n';
19
19
 
@@ -81,9 +81,21 @@ export const LinkControl = createControl( ( props: Props ) => {
81
81
  return;
82
82
  }
83
83
 
84
- setIsActive( ( prevState ) => ! prevState );
85
- setValue( isActive ? null : linkSessionValue?.value ?? null );
86
- setLinkSessionValue( { value, meta: { isEnabled: ! isActive } } );
84
+ const newState = ! isActive;
85
+ setIsActive( newState );
86
+
87
+ if ( ! newState && value !== null ) {
88
+ setValue( null );
89
+ }
90
+
91
+ if ( newState && linkSessionValue?.value ) {
92
+ setValue( linkSessionValue.value );
93
+ }
94
+
95
+ setLinkSessionValue( {
96
+ value: newState ? value : linkSessionValue?.value,
97
+ meta: { isEnabled: newState },
98
+ } );
87
99
  };
88
100
 
89
101
  const onOptionChange = ( newValue: number | null ) => {
@@ -105,7 +117,7 @@ export const LinkControl = createControl( ( props: Props ) => {
105
117
  ? {
106
118
  ...value,
107
119
  destination: urlPropTypeUtil.create( newValue ),
108
- label: null,
120
+ label: stringPropTypeUtil.create( '' ),
109
121
  }
110
122
  : null;
111
123
 
@@ -143,7 +155,6 @@ export const LinkControl = createControl( ( props: Props ) => {
143
155
  return (
144
156
  <PropProvider { ...propContext } value={ value } setValue={ setValue }>
145
157
  <Stack gap={ 1.5 }>
146
- <Divider />
147
158
  <Stack
148
159
  direction="row"
149
160
  sx={ {
@@ -2,35 +2,20 @@ import * as React from 'react';
2
2
  import { type ComponentProps, type ComponentType } from 'react';
3
3
  import { ErrorBoundary } from '@elementor/ui';
4
4
 
5
- import { useControlReplacement } from './create-control-replacement';
5
+ import { useControlReplacement } from './control-replacements';
6
6
 
7
7
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
8
  type AnyComponentType = ComponentType< any >;
9
9
 
10
- type Options = {
11
- supportsReplacements?: boolean;
12
- };
13
-
14
10
  const brandSymbol = Symbol( 'control' );
15
11
 
16
12
  export type ControlComponent< TComponent extends AnyComponentType = AnyComponentType > = TComponent & {
17
13
  [ brandSymbol ]: true;
18
14
  };
19
15
 
20
- export function createControl< T extends AnyComponentType >(
21
- Component: T,
22
- { supportsReplacements = true }: Options = {}
23
- ) {
16
+ export function createControl< T extends AnyComponentType >( Control: T ) {
24
17
  return ( ( props: ComponentProps< T > ) => {
25
- const ControlReplacement = useControlReplacement();
26
-
27
- if ( ControlReplacement && supportsReplacements ) {
28
- return (
29
- <ErrorBoundary fallback={ null }>
30
- <ControlReplacement { ...props } />
31
- </ErrorBoundary>
32
- );
33
- }
18
+ const Component = useControlReplacement( Control );
34
19
 
35
20
  return (
36
21
  <ErrorBoundary fallback={ null }>
package/src/index.ts CHANGED
@@ -34,7 +34,7 @@ export type { ToggleControlProps } from './controls/toggle-control';
34
34
  export type { FontCategory } from './controls/font-family-control/font-family-control';
35
35
 
36
36
  // providers
37
- export { createControlReplacement, ControlReplacementProvider } from './create-control-replacement';
37
+ export { createControlReplacementsRegistry, ControlReplacementsProvider } from './control-replacements';
38
38
  export { ControlActionsProvider, useControlActions } from './control-actions/control-actions-context';
39
39
  export { useBoundProp, PropProvider, PropKeyProvider } from './bound-prop-context';
40
40
  export { ControlAdornmentsProvider } from './control-adornments/control-adornments-context';
@@ -1,54 +0,0 @@
1
- import * as React from 'react';
2
- import { type ComponentType, createContext, useContext } from 'react';
3
- import { type PropValue } from '@elementor/editor-props';
4
-
5
- import { useBoundProp } from './bound-prop-context';
6
-
7
- type ReplaceWhenParams = {
8
- value: PropValue;
9
- };
10
-
11
- type CreateControlReplacement = {
12
- component: ComponentType;
13
- condition: ( { value }: ReplaceWhenParams ) => boolean;
14
- };
15
-
16
- const ControlReplacementContext = createContext< CreateControlReplacement | undefined >( undefined );
17
-
18
- export const ControlReplacementProvider = ( {
19
- component,
20
- condition,
21
- children,
22
- }: React.PropsWithChildren< CreateControlReplacement > ) => {
23
- return (
24
- <ControlReplacementContext.Provider value={ { component, condition } }>
25
- { children }
26
- </ControlReplacementContext.Provider>
27
- );
28
- };
29
- export const useControlReplacement = () => {
30
- const { value } = useBoundProp();
31
- const controlReplacement = useContext( ControlReplacementContext );
32
-
33
- let shouldReplace = false;
34
-
35
- try {
36
- shouldReplace = !! controlReplacement?.condition( { value } ) && !! controlReplacement.component;
37
- } catch {}
38
-
39
- return shouldReplace ? controlReplacement?.component : undefined;
40
- };
41
-
42
- export const createControlReplacement = () => {
43
- let controlReplacement: CreateControlReplacement;
44
-
45
- function replaceControl( { component, condition }: CreateControlReplacement ) {
46
- controlReplacement = { component, condition };
47
- }
48
-
49
- function getControlReplacement() {
50
- return controlReplacement;
51
- }
52
-
53
- return { replaceControl, getControlReplacement };
54
- };