@elementor/editor-editing-panel 4.0.0-manual → 4.0.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,6 +1,6 @@
1
1
  {
2
2
  "name": "@elementor/editor-editing-panel",
3
- "version": "4.0.0-manual",
3
+ "version": "4.0.0",
4
4
  "private": false,
5
5
  "author": "Elementor Team",
6
6
  "homepage": "https://elementor.com/",
@@ -39,28 +39,28 @@
39
39
  "dev": "tsup --config=../../tsup.dev.ts"
40
40
  },
41
41
  "dependencies": {
42
- "@elementor/editor": "4.0.0-manual",
43
- "@elementor/editor-canvas": "4.0.0-manual",
44
- "@elementor/editor-controls": "4.0.0-manual",
45
- "@elementor/editor-documents": "4.0.0-manual",
46
- "@elementor/editor-elements": "4.0.0-manual",
47
- "@elementor/editor-interactions": "4.0.0-manual",
48
- "@elementor/editor-panels": "4.0.0-manual",
49
- "@elementor/editor-props": "4.0.0-manual",
50
- "@elementor/editor-responsive": "4.0.0-manual",
51
- "@elementor/editor-styles": "4.0.0-manual",
52
- "@elementor/editor-styles-repository": "4.0.0-manual",
53
- "@elementor/editor-ui": "4.0.0-manual",
54
- "@elementor/editor-v1-adapters": "4.0.0-manual",
42
+ "@elementor/editor": "4.0.0",
43
+ "@elementor/editor-canvas": "4.0.0",
44
+ "@elementor/editor-controls": "4.0.0",
45
+ "@elementor/editor-documents": "4.0.0",
46
+ "@elementor/editor-elements": "4.0.0",
47
+ "@elementor/editor-interactions": "4.0.0",
48
+ "@elementor/editor-panels": "4.0.0",
49
+ "@elementor/editor-props": "4.0.0",
50
+ "@elementor/editor-responsive": "4.0.0",
51
+ "@elementor/editor-styles": "4.0.0",
52
+ "@elementor/editor-styles-repository": "4.0.0",
53
+ "@elementor/editor-ui": "4.0.0",
54
+ "@elementor/editor-v1-adapters": "4.0.0",
55
55
  "@elementor/icons": "^1.68.0",
56
- "@elementor/editor-variables": "4.0.0-manual",
57
- "@elementor/locations": "4.0.0-manual",
58
- "@elementor/menus": "4.0.0-manual",
59
- "@elementor/schema": "4.0.0-manual",
60
- "@elementor/session": "4.0.0-manual",
56
+ "@elementor/editor-variables": "4.0.0",
57
+ "@elementor/locations": "4.0.0",
58
+ "@elementor/menus": "4.0.0",
59
+ "@elementor/schema": "4.0.0",
60
+ "@elementor/session": "4.0.0",
61
61
  "@elementor/ui": "1.36.17",
62
- "@elementor/utils": "4.0.0-manual",
63
- "@elementor/wp-media": "4.0.0-manual",
62
+ "@elementor/utils": "4.0.0",
63
+ "@elementor/wp-media": "4.0.0",
64
64
  "@wordpress/i18n": "^5.13.0"
65
65
  },
66
66
  "peerDependencies": {
@@ -5,6 +5,8 @@ import { __ } from '@wordpress/i18n';
5
5
 
6
6
  import { StyleTabSection } from '../style-tab-section';
7
7
 
8
+ const TRACKING_DATA = { target_name: 'custom_css', location_l2: 'style' } as const;
9
+
8
10
  export const CustomCssSection = () => {
9
11
  const triggerRef = useRef< PromotionTriggerRef >( null );
10
12
 
@@ -14,7 +16,9 @@ export const CustomCssSection = () => {
14
16
  name: 'Custom CSS',
15
17
  title: __( 'Custom CSS', 'elementor' ),
16
18
  action: {
17
- component: <PromotionTrigger ref={ triggerRef } promotionKey="customCss" />,
19
+ component: (
20
+ <PromotionTrigger ref={ triggerRef } promotionKey="customCss" trackingData={ TRACKING_DATA } />
21
+ ),
18
22
  onClick: () => triggerRef.current?.toggle(),
19
23
  },
20
24
  } }
@@ -1,4 +1,5 @@
1
1
  import * as React from 'react';
2
+ import { useCallback, useEffect, useRef } from 'react';
2
3
  import { type StringPropValue } from '@elementor/editor-props';
3
4
  import { useSessionStorage } from '@elementor/session';
4
5
  import { __ } from '@wordpress/i18n';
@@ -28,47 +29,83 @@ type DimensionsValues = {
28
29
  'inset-inline-end': DimensionValue;
29
30
  };
30
31
 
32
+ type PositionDependentValues = DimensionsValues & {
33
+ 'z-index': number | undefined | null;
34
+ };
35
+
36
+ const POSITION_STATIC = 'static' as const;
37
+
31
38
  const POSITION_LABEL = __( 'Position', 'elementor' );
32
39
  const DIMENSIONS_LABEL = __( 'Dimensions', 'elementor' );
33
40
 
41
+ const POSITION_DEPENDENT_PROP_NAMES = [
42
+ 'inset-block-start',
43
+ 'inset-block-end',
44
+ 'inset-inline-start',
45
+ 'inset-inline-end',
46
+ 'z-index',
47
+ ] as const;
48
+
49
+ const CLEARED_POSITION_DEPENDENT_VALUES: Record< ( typeof POSITION_DEPENDENT_PROP_NAMES )[ number ], undefined > = {
50
+ 'inset-block-start': undefined,
51
+ 'inset-block-end': undefined,
52
+ 'inset-inline-start': undefined,
53
+ 'inset-inline-end': undefined,
54
+ 'z-index': undefined,
55
+ };
56
+
34
57
  export const PositionSection = () => {
35
58
  const { value: positionValue } = useStylesField< StringPropValue >( 'position', {
36
59
  history: { propDisplayName: POSITION_LABEL },
37
60
  } );
38
- const { values: dimensions, setValues: setDimensions } = useStylesFields< DimensionsValues >( [
39
- 'inset-block-start',
40
- 'inset-block-end',
41
- 'inset-inline-start',
42
- 'inset-inline-end',
43
- ] );
61
+ const { values: positionDependentValues, setValues: setPositionDependentValues } =
62
+ useStylesFields< PositionDependentValues >( [ ...POSITION_DEPENDENT_PROP_NAMES ] );
44
63
 
45
64
  const [ dimensionsValuesFromHistory, updateDimensionsHistory, clearDimensionsHistory ] = usePersistDimensions();
46
65
 
66
+ const clearPositionDependentProps = useCallback( () => {
67
+ const dimensions: DimensionsValues = {
68
+ 'inset-block-start': positionDependentValues?.[ 'inset-block-start' ],
69
+ 'inset-block-end': positionDependentValues?.[ 'inset-block-end' ],
70
+ 'inset-inline-start': positionDependentValues?.[ 'inset-inline-start' ],
71
+ 'inset-inline-end': positionDependentValues?.[ 'inset-inline-end' ],
72
+ };
73
+ const meta = { history: { propDisplayName: DIMENSIONS_LABEL } };
74
+ const hasValuesToClear =
75
+ Object.values( dimensions ).some( ( v ) => v !== null ) || positionDependentValues?.[ 'z-index' ] !== null;
76
+
77
+ if ( hasValuesToClear ) {
78
+ updateDimensionsHistory( dimensions );
79
+ setPositionDependentValues( CLEARED_POSITION_DEPENDENT_VALUES, meta );
80
+ }
81
+ }, [ positionDependentValues, updateDimensionsHistory, setPositionDependentValues ] );
82
+
83
+ const clearPositionDependentPropsRef = useRef( clearPositionDependentProps );
84
+ clearPositionDependentPropsRef.current = clearPositionDependentProps;
85
+
86
+ useEffect( () => {
87
+ if ( positionValue?.value === POSITION_STATIC || positionValue === null ) {
88
+ clearPositionDependentPropsRef.current();
89
+ }
90
+ }, [ positionValue ] );
91
+
47
92
  const onPositionChange = ( newPosition: string | null, previousPosition: string | null | undefined ) => {
48
93
  const meta = { history: { propDisplayName: DIMENSIONS_LABEL } };
49
94
 
50
- if ( newPosition === 'static' ) {
51
- if ( dimensions ) {
52
- updateDimensionsHistory( dimensions );
53
- setDimensions(
54
- {
55
- 'inset-block-start': undefined,
56
- 'inset-block-end': undefined,
57
- 'inset-inline-start': undefined,
58
- 'inset-inline-end': undefined,
59
- },
95
+ if ( newPosition === POSITION_STATIC ) {
96
+ clearPositionDependentProps();
97
+ } else if ( previousPosition === POSITION_STATIC ) {
98
+ if ( dimensionsValuesFromHistory ) {
99
+ setPositionDependentValues(
100
+ { ...dimensionsValuesFromHistory, 'z-index': undefined } as PositionDependentValues,
60
101
  meta
61
102
  );
62
- }
63
- } else if ( previousPosition === 'static' ) {
64
- if ( dimensionsValuesFromHistory ) {
65
- setDimensions( dimensionsValuesFromHistory, meta );
66
103
  clearDimensionsHistory();
67
104
  }
68
105
  }
69
106
  };
70
107
 
71
- const isNotStatic = positionValue && positionValue?.value !== 'static';
108
+ const isNotStatic = positionValue && positionValue?.value !== POSITION_STATIC;
72
109
 
73
110
  return (
74
111
  <SectionContent>
@@ -16,7 +16,12 @@ import { undoable } from '@elementor/editor-v1-adapters';
16
16
  import { __ } from '@wordpress/i18n';
17
17
 
18
18
  import { useElement } from '../contexts/element-context';
19
- import { extractOrderedDependencies, getUpdatedValues, type Values } from '../utils/prop-dependency-utils';
19
+ import {
20
+ extractOrderedDependencies,
21
+ getElementSettingsWithDefaults,
22
+ getUpdatedValues,
23
+ type Values,
24
+ } from '../utils/prop-dependency-utils';
20
25
  import { createTopLevelObjectType } from './create-top-level-object-type';
21
26
 
22
27
  type SettingsFieldProps = {
@@ -27,20 +32,8 @@ type SettingsFieldProps = {
27
32
 
28
33
  const HISTORY_DEBOUNCE_WAIT = 800;
29
34
 
30
- const getElementSettigsWithDefaults = ( propsSchema: PropsSchema, elementSettings?: Props ) => {
31
- const elementSettingsWithDefaults = { ...elementSettings };
32
- Object.keys( propsSchema ).forEach( ( key ) => {
33
- if ( ! ( key in elementSettingsWithDefaults ) ) {
34
- if ( propsSchema[ key ].default !== null ) {
35
- elementSettingsWithDefaults[ key ] = propsSchema[ key ].default as Values[ keyof Values ];
36
- }
37
- }
38
- } );
39
- return elementSettingsWithDefaults;
40
- };
41
-
42
35
  const extractDependencyEffect = ( bind: string, propsSchema: PropsSchema, currentElementSettings: Props ) => {
43
- const elementSettingsForDepCheck = getElementSettigsWithDefaults( propsSchema, currentElementSettings );
36
+ const elementSettingsForDepCheck = getElementSettingsWithDefaults( propsSchema, currentElementSettings );
44
37
  const propType = propsSchema[ bind ];
45
38
  const depCheck = isDependencyMet( propType?.dependencies, elementSettingsForDepCheck );
46
39
  const isHidden =
@@ -1,6 +1,6 @@
1
- import { Fragment, useState } from 'react';
2
1
  import * as React from 'react';
3
- import { useBoundProp } from '@elementor/editor-controls';
2
+ import { Fragment, useEffect, useState } from 'react';
3
+ import { trackUpgradePromotionClick, trackViewPromotion, useBoundProp } from '@elementor/editor-controls';
4
4
  import { CtaButton, PopoverHeader, PopoverMenuList, SearchField, SectionPopoverBody } from '@elementor/editor-ui';
5
5
  import { DatabaseIcon } from '@elementor/icons';
6
6
  import { Divider, Link, Stack, Typography, useTheme } from '@elementor/ui';
@@ -50,6 +50,14 @@ export const DynamicSelection = ( { close: closePopover, expired = false }: Dyna
50
50
 
51
51
  const hasNoDynamicTags = ! options.length && ! searchValue.trim();
52
52
 
53
+ useEffect( () => {
54
+ if ( hasNoDynamicTags ) {
55
+ trackViewPromotion( { target_name: 'dynamic_tags' } );
56
+ } else if ( expired ) {
57
+ trackViewPromotion( { target_name: 'dynamic_tags' } );
58
+ }
59
+ }, [ hasNoDynamicTags, expired ] );
60
+
53
61
  const handleSearch = ( value: string ) => {
54
62
  setSearchValue( value );
55
63
  };
@@ -170,7 +178,11 @@ const NoDynamicTags = () => (
170
178
  <Typography align="center" variant="caption" width={ PROMO_TEXT_WIDTH }>
171
179
  { __( 'Upgrade now to display your content dynamically.', 'elementor' ) }
172
180
  </Typography>
173
- <CtaButton size="small" href={ PRO_DYNAMIC_TAGS_URL } />
181
+ <CtaButton
182
+ size="small"
183
+ href={ PRO_DYNAMIC_TAGS_URL }
184
+ onClick={ () => trackUpgradePromotionClick( { target_name: 'dynamic_tags' } ) }
185
+ />
174
186
  </Stack>
175
187
  </>
176
188
  );
@@ -194,7 +206,12 @@ const ExpiredDynamicTags = () => (
194
206
  <Typography align="center" variant="caption" width={ PROMO_TEXT_WIDTH }>
195
207
  { __( 'Dynamic tags need Elementor Pro. Renew now to keep them active.', 'elementor' ) }
196
208
  </Typography>
197
- <CtaButton size="small" href={ RENEW_DYNAMIC_TAGS_URL } children={ __( 'Renew Now', 'elementor' ) } />
209
+ <CtaButton
210
+ size="small"
211
+ href={ RENEW_DYNAMIC_TAGS_URL }
212
+ onClick={ () => trackUpgradePromotionClick( { target_name: 'dynamic_tags' } ) }
213
+ children={ __( 'Renew Now', 'elementor' ) }
214
+ />
198
215
  </Stack>
199
216
  </>
200
217
  );
package/src/index.ts CHANGED
@@ -13,6 +13,7 @@ export { useClassesProp } from './contexts/classes-prop-context';
13
13
  export { ElementProvider, useElement } from './contexts/element-context';
14
14
  export { useStyle } from './contexts/style-context';
15
15
  export { Control as BaseControl } from './controls-registry/control';
16
+ export { ControlTypeContainer } from './controls-registry/control-type-container';
16
17
  export { controlsRegistry, type ControlType } from './controls-registry/controls-registry';
17
18
  export { StylesProviderCannotUpdatePropsError } from './errors';
18
19
  export { createTopLevelObjectType } from './controls-registry/create-top-level-object-type';
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { Typography } from '@elementor/ui';
2
+ import { Tooltip, Typography } from '@elementor/ui';
3
3
 
4
4
  type Props = {
5
5
  index: number;
@@ -8,21 +8,24 @@ type Props = {
8
8
 
9
9
  export const ValueComponent = ( { index, value }: Props ) => {
10
10
  return (
11
- <Typography
12
- variant="caption"
13
- color="text.tertiary"
14
- sx={ {
15
- mt: '1px',
16
- textDecoration: index === 0 ? 'none' : 'line-through',
17
- overflow: 'hidden',
18
- textOverflow: 'ellipsis',
19
- whiteSpace: 'nowrap',
20
- pl: 2.5,
21
- minWidth: 0,
22
- maxWidth: '100%',
23
- } }
24
- >
25
- { value }
26
- </Typography>
11
+ <Tooltip title={ value } placement="top">
12
+ <Typography
13
+ variant="caption"
14
+ color="text.tertiary"
15
+ sx={ {
16
+ mt: '1px',
17
+ textDecoration: index === 0 ? 'none' : 'line-through',
18
+ overflow: 'hidden',
19
+ display: '-webkit-box',
20
+ WebkitLineClamp: 1,
21
+ WebkitBoxOrient: 'vertical',
22
+ pl: 2.5,
23
+ minWidth: 0,
24
+ maxWidth: '100%',
25
+ } }
26
+ >
27
+ { value }
28
+ </Typography>
29
+ </Tooltip>
27
30
  );
28
31
  };
@@ -125,7 +125,7 @@ export const StylesInheritanceInfotip = ( {
125
125
  },
126
126
  } }
127
127
  >
128
- <Stack gap={ 1.5 } sx={ { pl: 3, pr: 1, pb: 2 } } role="list">
128
+ <Stack gap={ 1.5 } sx={ { pl: 2, pr: 1, pt: 1.5, pb: 1.5 } } role="list">
129
129
  { items.map( ( item, index ) => {
130
130
  return (
131
131
  <Box
@@ -235,15 +235,13 @@ function TooltipOrInfotip( {
235
235
  sx: { mx: 2 },
236
236
  },
237
237
  } }
238
- slotProps={ {
239
- popper: {
240
- modifiers: [
241
- {
242
- name: 'offset',
243
- options: { offset: [ offsetX, 0 ] },
244
- },
245
- ],
246
- },
238
+ PopperProps={ {
239
+ modifiers: [
240
+ {
241
+ name: 'offset',
242
+ options: { offset: [ offsetX, 0 ] },
243
+ },
244
+ ],
247
245
  } }
248
246
  >
249
247
  { children }
@@ -53,7 +53,7 @@ function registerCustomTransformers( originalStyleTransformers: ReturnType< type
53
53
  );
54
54
  stylesInheritanceTransformersRegistry.register(
55
55
  'transition',
56
- createRepeaterToItemsTransformer( originalStyleTransformers.transition, ', ' )
56
+ createRepeaterToItemsTransformer( originalStyleTransformers.transition )
57
57
  );
58
58
 
59
59
  [ 'background-overlay', 'box-shadow', 'transform-functions' ].forEach( ( propType ) =>
@@ -1,20 +1,28 @@
1
1
  import * as React from 'react';
2
2
  import { type ReactNode } from 'react';
3
3
  import { createTransformer } from '@elementor/editor-canvas';
4
- import { Stack } from '@elementor/ui';
5
4
 
6
- type ArrayValues = ReactNode[];
5
+ type ArrayValues = ReactNode | ReactNode[];
7
6
 
8
7
  export const arrayTransformer = createTransformer( ( values: ArrayValues[] ) => {
9
8
  if ( ! values || values.length === 0 ) {
10
9
  return null;
11
10
  }
12
11
 
12
+ const allStrings = values.every( ( item ) => typeof item === 'string' || typeof item === 'number' );
13
+
14
+ if ( allStrings ) {
15
+ return ( values as ( string | number )[] ).join( ' ' );
16
+ }
17
+
13
18
  return (
14
- <Stack direction="column">
19
+ <>
15
20
  { values.map( ( item, index ) => (
16
- <Stack key={ index }>{ item }</Stack>
21
+ <React.Fragment key={ index }>
22
+ { index > 0 && ' ' }
23
+ { item }
24
+ </React.Fragment>
17
25
  ) ) }
18
- </Stack>
26
+ </>
19
27
  );
20
28
  } );
@@ -1,13 +1,13 @@
1
1
  import * as React from 'react';
2
+ import { type ReactNode } from 'react';
2
3
  import { createTransformer } from '@elementor/editor-canvas';
3
- import { Stack } from '@elementor/ui';
4
4
 
5
5
  type Shadow = {
6
6
  hOffset?: string;
7
7
  vOffset?: string;
8
8
  blur?: string;
9
9
  spread?: string;
10
- color?: string;
10
+ color?: ReactNode;
11
11
  position?: string | null;
12
12
  };
13
13
 
@@ -23,10 +23,8 @@ export const boxShadowTransformer = createTransformer( ( value: Shadow ) => {
23
23
  const positionValue = position || 'outset';
24
24
 
25
25
  return (
26
- <Stack direction="column" gap={ 0.5 } pb={ 1 }>
27
- <span>
28
- { colorValue } { positionValue }, { sizes }
29
- </span>
30
- </Stack>
26
+ <>
27
+ { colorValue } { positionValue }, { sizes }
28
+ </>
31
29
  );
32
30
  } );
@@ -1,8 +1,6 @@
1
- import * as React from 'react';
2
1
  import { type AnyTransformer, createTransformer } from '@elementor/editor-canvas';
3
- import { Stack } from '@elementor/ui';
4
2
 
5
- export const createRepeaterToItemsTransformer = ( originalTransformer: AnyTransformer, separator: string = ' ' ) => {
3
+ export const createRepeaterToItemsTransformer = ( originalTransformer: AnyTransformer ) => {
6
4
  return createTransformer( ( value: string, options: { key: string; signal?: AbortSignal } ) => {
7
5
  const stringResult = originalTransformer( value, options );
8
6
 
@@ -10,18 +8,6 @@ export const createRepeaterToItemsTransformer = ( originalTransformer: AnyTransf
10
8
  return stringResult;
11
9
  }
12
10
 
13
- const parts = stringResult.split( separator ).filter( Boolean );
14
-
15
- if ( parts.length <= 1 ) {
16
- return stringResult;
17
- }
18
-
19
- return (
20
- <Stack direction="column" gap={ 0.5 }>
21
- { parts.map( ( part, index ) => (
22
- <Stack key={ index }>{ part.trim() }</Stack>
23
- ) ) }
24
- </Stack>
25
- );
11
+ return stringResult;
26
12
  } );
27
13
  };
@@ -3,6 +3,7 @@ import {
3
3
  type DependencyTerm,
4
4
  extractValue,
5
5
  isDependencyMet,
6
+ type Props,
6
7
  type PropsSchema,
7
8
  type PropType,
8
9
  type TransformablePropValue,
@@ -13,6 +14,17 @@ type Value = TransformablePropValue< string > | null;
13
14
 
14
15
  export type Values = Record< string, Value >;
15
16
 
17
+ export function getElementSettingsWithDefaults( propsSchema: PropsSchema, elementSettings?: Props ): Values {
18
+ const elementSettingsWithDefaults = { ...elementSettings };
19
+ Object.keys( propsSchema ).forEach( ( key ) => {
20
+ if ( elementSettingsWithDefaults[ key ] === null && propsSchema[ key ].default !== null ) {
21
+ elementSettingsWithDefaults[ key ] = propsSchema[ key ].default as Values[ keyof Values ];
22
+ }
23
+ } );
24
+
25
+ return elementSettingsWithDefaults as Values;
26
+ }
27
+
16
28
  export function extractOrderedDependencies( dependenciesPerTargetMapping: Record< string, string[] > ): string[] {
17
29
  return Object.values( dependenciesPerTargetMapping )
18
30
  .flat()