@elementor/editor-editing-panel 1.39.0 → 1.41.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 (50) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/dist/index.d.mts +9 -0
  3. package/dist/index.d.ts +9 -0
  4. package/dist/index.js +1182 -735
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +1075 -617
  7. package/dist/index.mjs.map +1 -1
  8. package/package.json +7 -6
  9. package/src/action.tsx +26 -0
  10. package/src/components/add-or-remove-content.tsx +11 -3
  11. package/src/components/creatable-autocomplete/creatable-autocomplete.tsx +6 -2
  12. package/src/components/css-classes/css-class-item.tsx +3 -2
  13. package/src/components/css-classes/css-class-menu.tsx +15 -5
  14. package/src/components/css-classes/css-class-selector.tsx +2 -1
  15. package/src/components/css-classes/use-apply-and-unapply-class.ts +8 -4
  16. package/src/components/section-content.tsx +16 -6
  17. package/src/components/style-sections/background-section/background-section.tsx +6 -3
  18. package/src/components/style-sections/border-section/border-field.tsx +3 -0
  19. package/src/components/style-sections/layout-section/display-field.tsx +2 -1
  20. package/src/components/style-sections/layout-section/flex-order-field.tsx +5 -2
  21. package/src/components/style-sections/layout-section/flex-size-field.tsx +16 -12
  22. package/src/components/style-sections/size-section/object-fit-field.tsx +1 -1
  23. package/src/components/style-sections/size-section/object-position-field.tsx +1 -1
  24. package/src/components/style-sections/size-section/size-section.tsx +12 -11
  25. package/src/components/style-sections/typography-section/text-stroke-field.tsx +3 -0
  26. package/src/components/style-tab.tsx +1 -1
  27. package/src/contexts/style-context.tsx +11 -2
  28. package/src/contexts/styles-inheritance-context.tsx +9 -7
  29. package/src/controls-actions.ts +2 -0
  30. package/src/controls-registry/styles-field.tsx +3 -0
  31. package/src/init.ts +11 -1
  32. package/src/reset-style-props.tsx +31 -0
  33. package/src/styles-inheritance/components/action-icons.tsx +8 -0
  34. package/src/styles-inheritance/components/breakpoint-icon.tsx +47 -0
  35. package/src/styles-inheritance/components/index.ts +4 -0
  36. package/src/styles-inheritance/components/label-chip.tsx +43 -0
  37. package/src/styles-inheritance/components/value-component.tsx +25 -0
  38. package/src/styles-inheritance/consts.ts +17 -0
  39. package/src/styles-inheritance/create-styles-inheritance.ts +50 -12
  40. package/src/{hooks → styles-inheritance/hooks}/use-normalized-inheritance-chain-items.tsx +41 -11
  41. package/src/styles-inheritance/init-styles-inheritance-transformers.ts +38 -0
  42. package/src/styles-inheritance/init.ts +8 -0
  43. package/src/styles-inheritance/styles-inheritance-indicator.tsx +35 -32
  44. package/src/styles-inheritance/styles-inheritance-infotip.tsx +113 -19
  45. package/src/styles-inheritance/styles-inheritance-transformers-registry.tsx +3 -0
  46. package/src/styles-inheritance/transformers/background-color-overlay-transformer.tsx +27 -0
  47. package/src/styles-inheritance/transformers/background-gradient-overlay-transformer.tsx +50 -0
  48. package/src/styles-inheritance/transformers/background-image-overlay-transformer.tsx +79 -0
  49. package/src/styles-inheritance/transformers/background-overlay-transformer.tsx +20 -0
  50. package/src/styles-inheritance/types.ts +6 -2
package/src/init.ts CHANGED
@@ -1,11 +1,14 @@
1
1
  import { injectIntoLogic } from '@elementor/editor';
2
2
  import { PrefetchUserData } from '@elementor/editor-current-user';
3
3
  import { __registerPanel as registerPanel } from '@elementor/editor-panels';
4
- import { blockCommand } from '@elementor/editor-v1-adapters';
4
+ import { blockCommand, isExperimentActive } from '@elementor/editor-v1-adapters';
5
5
 
6
6
  import { EditingPanelHooks } from './components/editing-panel-hooks';
7
7
  import { init as initDynamics } from './dynamics/init';
8
8
  import { panel } from './panel';
9
+ import { initResetStyleProps } from './reset-style-props';
10
+ import { init as initStylesInheritance } from './styles-inheritance/init';
11
+ import { EXPERIMENTAL_FEATURES } from './sync/experiments-flags';
9
12
  import { isAtomicWidgetSelected } from './sync/is-atomic-widget-selected';
10
13
 
11
14
  export function init() {
@@ -24,6 +27,13 @@ export function init() {
24
27
 
25
28
  // TODO: Move it from here once we have dynamic package.
26
29
  initDynamics();
30
+
31
+ // TODO: Move it from here once we have styles-inheritance package.
32
+ initStylesInheritance();
33
+
34
+ if ( isExperimentActive( EXPERIMENTAL_FEATURES.V_3_30 ) ) {
35
+ initResetStyleProps();
36
+ }
27
37
  }
28
38
 
29
39
  const blockV1Panel = () => {
@@ -0,0 +1,31 @@
1
+ import { useBoundProp } from '@elementor/editor-controls';
2
+ import { BrushBigIcon } from '@elementor/icons';
3
+ import { __ } from '@wordpress/i18n';
4
+
5
+ import { useIsStyle } from './contexts/style-context';
6
+ import { controlActionsMenu } from './controls-actions';
7
+
8
+ const { registerAction } = controlActionsMenu;
9
+
10
+ export function initResetStyleProps() {
11
+ registerAction( {
12
+ id: 'reset-style-value',
13
+ useProps: useResetStyleValueProps,
14
+ } );
15
+ }
16
+
17
+ // Temporary fix for the issue with ControlToggleButtonGroup.
18
+ const EXCLUDED_BINDS = [ 'order', 'flex-grow', 'flex-shrink', 'flex-basis' ];
19
+
20
+ export function useResetStyleValueProps() {
21
+ const isStyle = useIsStyle();
22
+ const { value, setValue, path, bind } = useBoundProp();
23
+
24
+ return {
25
+ visible:
26
+ isStyle && value !== null && value !== undefined && path.length <= 2 && ! EXCLUDED_BINDS.includes( bind ),
27
+ title: __( 'Clear', 'elementor' ),
28
+ icon: BrushBigIcon,
29
+ onClick: () => setValue( null ),
30
+ };
31
+ }
@@ -0,0 +1,8 @@
1
+ import * as React from 'react';
2
+ import { Box } from '@elementor/ui';
3
+
4
+ export const ActionIcons = () => (
5
+ <Box display="flex" gap={ 0.5 } alignItems="center">
6
+ { /* Action Slot */ }
7
+ </Box>
8
+ );
@@ -0,0 +1,47 @@
1
+ import * as React from 'react';
2
+ import { type BreakpointId, useBreakpoints } from '@elementor/editor-responsive';
3
+ import {
4
+ DesktopIcon,
5
+ LaptopIcon,
6
+ MobileLandscapeIcon,
7
+ MobilePortraitIcon,
8
+ TabletLandscapeIcon,
9
+ TabletPortraitIcon,
10
+ WidescreenIcon,
11
+ } from '@elementor/icons';
12
+ import { Tooltip } from '@elementor/ui';
13
+
14
+ type Props = {
15
+ breakpoint?: BreakpointId | null;
16
+ };
17
+
18
+ const SIZE = 'tiny';
19
+ const DEFAULT_BREAKPOINT = 'desktop';
20
+
21
+ const breakpointIconMap: Record< string, React.ElementType > = {
22
+ widescreen: WidescreenIcon,
23
+ desktop: DesktopIcon,
24
+ laptop: LaptopIcon,
25
+ tablet_extra: TabletLandscapeIcon,
26
+ tablet: TabletPortraitIcon,
27
+ mobile_extra: MobileLandscapeIcon,
28
+ mobile: MobilePortraitIcon,
29
+ };
30
+
31
+ export const BreakpointIcon = ( { breakpoint }: Props ) => {
32
+ const breakpoints = useBreakpoints();
33
+ const currentBreakpoint = breakpoint || DEFAULT_BREAKPOINT;
34
+ const IconComponent = breakpointIconMap[ currentBreakpoint ];
35
+
36
+ if ( ! IconComponent ) {
37
+ return null;
38
+ }
39
+
40
+ const breakpointLabel = breakpoints.find( ( breakpointItem ) => breakpointItem.id === currentBreakpoint )?.label;
41
+
42
+ return (
43
+ <Tooltip title={ breakpointLabel } placement="top">
44
+ <IconComponent fontSize={ SIZE } sx={ { mt: '2px' } } />
45
+ </Tooltip>
46
+ );
47
+ };
@@ -0,0 +1,4 @@
1
+ export { BreakpointIcon } from './breakpoint-icon';
2
+ export { LabelChip } from './label-chip';
3
+ export { ValueComponent } from './value-component';
4
+ export { ActionIcons } from './action-icons';
@@ -0,0 +1,43 @@
1
+ import * as React from 'react';
2
+ import { ELEMENTS_BASE_STYLES_PROVIDER_KEY } from '@elementor/editor-styles-repository';
3
+ import { InfoCircleIcon } from '@elementor/icons';
4
+ import { Chip, type Theme, Tooltip } from '@elementor/ui';
5
+ import { __ } from '@wordpress/i18n';
6
+
7
+ type Props = {
8
+ displayLabel: string;
9
+ provider?: string;
10
+ };
11
+
12
+ const SIZE = 'tiny';
13
+
14
+ export const LabelChip = ( { displayLabel, provider }: Props ) => {
15
+ return (
16
+ <Chip
17
+ label={ displayLabel }
18
+ size={ SIZE }
19
+ color="global"
20
+ variant="standard"
21
+ state="enabled"
22
+ icon={
23
+ provider === ELEMENTS_BASE_STYLES_PROVIDER_KEY ? (
24
+ <Tooltip title={ __( 'Inherited from base styles', 'elementor' ) } placement="top">
25
+ <InfoCircleIcon fontSize={ SIZE } />
26
+ </Tooltip>
27
+ ) : undefined
28
+ }
29
+ sx={ ( theme: Theme ) => ( {
30
+ lineHeight: 1,
31
+ flexWrap: 'nowrap',
32
+ alignItems: 'center',
33
+ borderRadius: `${ theme.shape.borderRadius * 0.75 }px`,
34
+ flexDirection: 'row-reverse',
35
+ '.MuiChip-label': {
36
+ overflow: 'hidden',
37
+ textOverflow: 'ellipsis',
38
+ whiteSpace: 'nowrap',
39
+ },
40
+ } ) }
41
+ />
42
+ );
43
+ };
@@ -0,0 +1,25 @@
1
+ import * as React from 'react';
2
+ import { Typography } from '@elementor/ui';
3
+
4
+ type Props = {
5
+ index: number;
6
+ value: React.ReactNode;
7
+ };
8
+
9
+ export const ValueComponent = ( { index, value }: Props ) => {
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
+ } }
21
+ >
22
+ { value }
23
+ </Typography>
24
+ );
25
+ };
@@ -0,0 +1,17 @@
1
+ import { isExperimentActive } from '@elementor/editor-v1-adapters';
2
+
3
+ // the following prop types' style transformers would be ignored to provide alternative transformers for the styles inheritance popover
4
+ export const excludePropTypeTransformers = new Set( [
5
+ 'background-color-overlay',
6
+ 'background-image-overlay',
7
+ 'background-gradient-overlay',
8
+ 'gradient-color-stop',
9
+ 'color-stop',
10
+ 'background-image-position-offset',
11
+ 'background-image-size-scale',
12
+ 'image-src',
13
+ 'image',
14
+ 'background-overlay',
15
+ ] );
16
+
17
+ export const isUsingIndicatorPopover = () => isExperimentActive( 'e_indications_popover' );
@@ -1,17 +1,21 @@
1
- import { isEmpty, isTransformable, type PropKey, type PropValue } from '@elementor/editor-props';
1
+ import {
2
+ isEmpty,
3
+ isTransformable,
4
+ type PropKey,
5
+ type PropType,
6
+ type PropValue,
7
+ type UnionPropType,
8
+ } from '@elementor/editor-props';
2
9
  import { type BreakpointNode } from '@elementor/editor-responsive';
3
10
  import { type StyleDefinition } from '@elementor/editor-styles';
4
11
 
5
12
  import { getProviderByStyleId } from '../contexts/style-context';
6
13
  import { createSnapshotsManager } from './create-snapshots-manager';
7
- import {
8
- type BreakpointsStatesStyles,
9
- type StyleInheritanceMetaProps,
10
- type StylesInheritanceAPI,
11
- type StylesInheritanceSnapshot,
12
- } from './types';
14
+ import { type BreakpointsStatesStyles, type StyleInheritanceMetaProps, type StylesInheritanceAPI } from './types';
13
15
  import { getBreakpointKey, getStateKey } from './utils';
14
16
 
17
+ type ValidPropType = Exclude< PropType, UnionPropType >;
18
+
15
19
  export function createStylesInheritance(
16
20
  styleDefs: StyleDefinition[],
17
21
  breakpointsRoot: BreakpointNode
@@ -23,16 +27,18 @@ export function createStylesInheritance(
23
27
 
24
28
  return {
25
29
  getSnapshot: createSnapshotsManager( getStyles, breakpointsRoot ),
26
- getInheritanceChain: ( snapshot: StylesInheritanceSnapshot, path: string[] ) => {
30
+ getInheritanceChain: ( snapshot, path, topLevelPropType ) => {
27
31
  const [ field, ...nextFields ] = path;
28
32
 
29
33
  let inheritanceChain = snapshot[ field ] ?? [];
30
34
 
31
35
  if ( nextFields.length > 0 ) {
36
+ const filterPropType = getFilterPropType( topLevelPropType, nextFields );
37
+
32
38
  inheritanceChain = inheritanceChain
33
39
  .map( ( { value: styleValue, ...rest } ) => ( {
34
40
  ...rest,
35
- value: getValueByPath( styleValue, nextFields ),
41
+ value: getValueByPath( styleValue, nextFields, filterPropType ),
36
42
  } ) )
37
43
  .filter( ( { value: styleValue } ) => ! isEmpty( styleValue ) );
38
44
  }
@@ -77,24 +83,56 @@ function buildStyleVariantsByMetaMapping( styleDefs: StyleDefinition[] ): Breakp
77
83
  return breakpointStateSlots;
78
84
  }
79
85
 
80
- function getValueByPath( value: PropValue, path: PropKey[] ): PropValue {
86
+ function getValueByPath( value: PropValue, path: PropKey[], filterPropType: ValidPropType | null ): PropValue {
81
87
  if ( ! value || typeof value !== 'object' ) {
82
88
  return null;
83
89
  }
84
90
 
91
+ if ( shouldUseOriginalValue( filterPropType, value ) ) {
92
+ return value;
93
+ }
94
+
85
95
  return path.reduce( ( currentScope: PropValue, key: PropKey ): PropValue | null => {
86
96
  if ( ! currentScope ) {
87
97
  return null;
88
98
  }
89
99
 
90
100
  if ( isTransformable( currentScope ) ) {
91
- return currentScope.value?.[ key ];
101
+ return currentScope.value?.[ key ] ?? null;
92
102
  }
93
103
 
94
104
  if ( typeof currentScope === 'object' ) {
95
- return currentScope[ key as keyof typeof currentScope ];
105
+ return currentScope[ key as keyof typeof currentScope ] ?? null;
96
106
  }
97
107
 
98
108
  return null;
99
109
  }, value );
100
110
  }
111
+
112
+ function shouldUseOriginalValue( filterPropType: ValidPropType | null, value: PropValue ): boolean {
113
+ return !! filterPropType && isTransformable( value ) && filterPropType.key !== value.$$type;
114
+ }
115
+
116
+ const getFilterPropType = ( propType: PropType, path: string[] ): ValidPropType | null => {
117
+ if ( ! propType || propType.kind !== 'union' ) {
118
+ return null;
119
+ }
120
+
121
+ return (
122
+ Object.values( propType.prop_types ).find( ( type: PropType ) => {
123
+ return !! path.reduce( ( currentScope: PropType | null, key: string ) => {
124
+ if ( currentScope?.kind !== 'object' ) {
125
+ return null;
126
+ }
127
+
128
+ const { shape } = currentScope;
129
+
130
+ if ( shape[ key ] ) {
131
+ return shape[ key ];
132
+ }
133
+
134
+ return null;
135
+ }, type );
136
+ } ) ?? null
137
+ );
138
+ };
@@ -1,14 +1,17 @@
1
- import { type ReactNode, useEffect, useState } from 'react';
1
+ import { isValidElement, type ReactNode, useEffect, useState } from 'react';
2
2
  import { type PropsResolver } from '@elementor/editor-canvas';
3
3
  import { type PropKey } from '@elementor/editor-props';
4
4
  import { type StyleDefinitionVariant } from '@elementor/editor-styles';
5
+ import { ELEMENTS_BASE_STYLES_PROVIDER_KEY } from '@elementor/editor-styles-repository';
6
+ import { __ } from '@wordpress/i18n';
5
7
 
6
- import { type SnapshotPropValue } from '../styles-inheritance/types';
8
+ import { type SnapshotPropValue } from '../types';
7
9
 
8
10
  const MAXIMUM_ITEMS = 2;
9
11
 
10
12
  type NormalizedItem = {
11
13
  id: string | number;
14
+ provider: string;
12
15
  breakpoint?: StyleDefinitionVariant[ 'meta' ][ 'breakpoint' ];
13
16
  displayLabel: string;
14
17
  value: ReactNode | string;
@@ -25,11 +28,20 @@ export const useNormalizedInheritanceChainItems = (
25
28
  ( async () => {
26
29
  const normalizedItems = await Promise.all(
27
30
  inheritanceChain
28
- .filter( ( item ) => item.style?.label )
31
+ .filter( ( { style } ) => style )
29
32
  .map( ( item, index ) => normalizeInheritanceItem( item, index, bind, resolve ) )
30
33
  );
31
34
 
32
- const validItems = normalizedItems.filter( ( item ) => item.value !== '' ).slice( 0, MAXIMUM_ITEMS );
35
+ const validItems = normalizedItems
36
+ .map( ( item ) => ( {
37
+ ...item,
38
+ displayLabel:
39
+ ELEMENTS_BASE_STYLES_PROVIDER_KEY !== item.provider
40
+ ? item.displayLabel
41
+ : __( 'Base', 'elementor' ),
42
+ } ) )
43
+ .filter( ( item ) => ! item.value || item.displayLabel !== '' )
44
+ .slice( 0, MAXIMUM_ITEMS );
33
45
 
34
46
  setItems( validItems );
35
47
  } )();
@@ -38,19 +50,27 @@ export const useNormalizedInheritanceChainItems = (
38
50
  return items;
39
51
  };
40
52
 
53
+ const DEFAULT_BREAKPOINT = 'desktop';
54
+
41
55
  export const normalizeInheritanceItem = async (
42
56
  item: SnapshotPropValue,
43
57
  index: number,
44
58
  bind: PropKey,
45
59
  resolve: PropsResolver
46
60
  ): Promise< NormalizedItem > => {
47
- const state = item.variant?.meta?.state || '';
48
- const label = item.style?.label || '';
49
- const displayLabel = state ? `${ label }:${ state }` : label;
61
+ const {
62
+ variant: {
63
+ meta: { state, breakpoint },
64
+ },
65
+ style: { label, id },
66
+ } = item;
67
+
68
+ const displayLabel = `${ label }${ state ? ':' + state : '' }`;
50
69
 
51
70
  return {
52
- id: item.style?.id ? item.style?.id + state : index,
53
- breakpoint: item.variant?.meta?.breakpoint,
71
+ id: id ? id + ( state ?? '' ) : index,
72
+ provider: item.provider || '',
73
+ breakpoint: breakpoint ?? DEFAULT_BREAKPOINT,
54
74
  displayLabel,
55
75
  value: await getTransformedValue( item, bind, resolve ),
56
76
  };
@@ -60,7 +80,7 @@ const getTransformedValue = async (
60
80
  item: SnapshotPropValue,
61
81
  bind: PropKey,
62
82
  resolve: PropsResolver
63
- ): Promise< string > => {
83
+ ): Promise< ReactNode | string > => {
64
84
  try {
65
85
  const result = await resolve( {
66
86
  props: {
@@ -68,7 +88,17 @@ const getTransformedValue = async (
68
88
  },
69
89
  } );
70
90
 
71
- return Object.values( result ).join( ' ' );
91
+ const value = result?.[ bind ] ?? result;
92
+
93
+ if ( isValidElement( value ) ) {
94
+ return value;
95
+ }
96
+
97
+ if ( typeof value === 'object' ) {
98
+ return JSON.stringify( value );
99
+ }
100
+
101
+ return String( value );
72
102
  } catch {
73
103
  return '';
74
104
  }
@@ -0,0 +1,38 @@
1
+ import { createTransformer, styleTransformersRegistry } from '@elementor/editor-canvas';
2
+
3
+ import { excludePropTypeTransformers } from './consts';
4
+ import { stylesInheritanceTransformersRegistry } from './styles-inheritance-transformers-registry';
5
+ import { backgroundColorOverlayTransformer } from './transformers/background-color-overlay-transformer';
6
+ import { backgroundGradientOverlayTransformer } from './transformers/background-gradient-overlay-transformer';
7
+ import { backgroundImageOverlayTransformer } from './transformers/background-image-overlay-transformer';
8
+ import { backgroundOverlayTransformer } from './transformers/background-overlay-transformer';
9
+
10
+ export function initStylesInheritanceTransformers() {
11
+ const originalStyleTransformers = styleTransformersRegistry.all();
12
+
13
+ Object.entries( originalStyleTransformers ).forEach( ( [ propType, transformer ] ) => {
14
+ if ( excludePropTypeTransformers.has( propType ) ) {
15
+ return;
16
+ }
17
+
18
+ stylesInheritanceTransformersRegistry.register( propType, transformer );
19
+ } );
20
+
21
+ stylesInheritanceTransformersRegistry.registerFallback(
22
+ createTransformer( ( value: unknown ) => {
23
+ return value;
24
+ } )
25
+ );
26
+
27
+ registerCustomTransformers();
28
+ }
29
+
30
+ function registerCustomTransformers() {
31
+ stylesInheritanceTransformersRegistry.register( 'background-color-overlay', backgroundColorOverlayTransformer );
32
+ stylesInheritanceTransformersRegistry.register(
33
+ 'background-gradient-overlay',
34
+ backgroundGradientOverlayTransformer
35
+ );
36
+ stylesInheritanceTransformersRegistry.register( 'background-image-overlay', backgroundImageOverlayTransformer );
37
+ stylesInheritanceTransformersRegistry.register( 'background-overlay', backgroundOverlayTransformer );
38
+ }
@@ -0,0 +1,8 @@
1
+ import { isUsingIndicatorPopover } from './consts';
2
+ import { initStylesInheritanceTransformers } from './init-styles-inheritance-transformers';
3
+
4
+ export const init = () => {
5
+ if ( isUsingIndicatorPopover() ) {
6
+ initStylesInheritanceTransformers();
7
+ }
8
+ };
@@ -1,24 +1,23 @@
1
1
  import * as React from 'react';
2
- import { useState } from 'react';
3
2
  import { useBoundProp } from '@elementor/editor-controls';
4
3
  import { isEmpty } from '@elementor/editor-props';
5
4
  import { ELEMENTS_BASE_STYLES_PROVIDER_KEY, isElementsStylesProvider } from '@elementor/editor-styles-repository';
6
5
  import { isExperimentActive } from '@elementor/editor-v1-adapters';
7
- import { IconButton, Infotip } from '@elementor/ui';
6
+ import { Tooltip } from '@elementor/ui';
8
7
  import { __ } from '@wordpress/i18n';
9
8
 
10
9
  import { StyleIndicator } from '../components/style-indicator';
11
10
  import { useStyle } from '../contexts/style-context';
12
11
  import { useStylesInheritanceChain } from '../contexts/styles-inheritance-context';
12
+ import { EXPERIMENTAL_FEATURES } from '../sync/experiments-flags';
13
+ import { isUsingIndicatorPopover } from './consts';
13
14
  import { StyleIndicatorInfotip } from './styles-inheritance-infotip';
14
15
 
15
16
  export const StylesInheritanceIndicator = () => {
16
- const [ open, setOpen ] = useState( false );
17
-
18
- const { value, path, propType } = useBoundProp();
17
+ const { path, propType } = useBoundProp();
19
18
  const { id: currentStyleId, provider: currentStyleProvider, meta: currentStyleMeta } = useStyle();
20
19
 
21
- const isUsingNestedProps = isExperimentActive( 'e_v_3_30' );
20
+ const isUsingNestedProps = isExperimentActive( EXPERIMENTAL_FEATURES.V_3_30 );
22
21
 
23
22
  const finalPath = isUsingNestedProps ? path : path.slice( 0, 1 );
24
23
 
@@ -28,44 +27,48 @@ export const StylesInheritanceIndicator = () => {
28
27
  return null;
29
28
  }
30
29
 
31
- const [ { style, variant, provider } ] = inheritanceChain;
30
+ const currentItem = inheritanceChain.find(
31
+ ( {
32
+ style,
33
+ variant: {
34
+ meta: { breakpoint, state },
35
+ },
36
+ } ) =>
37
+ style.id === currentStyleId &&
38
+ breakpoint === currentStyleMeta.breakpoint &&
39
+ state === currentStyleMeta.state
40
+ );
32
41
 
33
- if ( provider === ELEMENTS_BASE_STYLES_PROVIDER_KEY ) {
34
- return null;
35
- }
42
+ const hasValue = ! isEmpty( currentItem?.value );
36
43
 
37
- const { breakpoint, state } = variant.meta;
44
+ const [ actualStyle ] = inheritanceChain;
38
45
 
39
- const isFinalValue =
40
- style.id === currentStyleId && breakpoint === currentStyleMeta.breakpoint && state === currentStyleMeta.state;
46
+ if ( actualStyle.provider === ELEMENTS_BASE_STYLES_PROVIDER_KEY ) {
47
+ return null;
48
+ }
41
49
 
42
- const hasValue = ! isEmpty( value );
50
+ const isFinalValue = currentItem === actualStyle;
43
51
 
44
52
  const label = getLabel( { isFinalValue, hasValue } );
45
53
  const variantType = getVariant( { isFinalValue, hasValue, currentStyleProvider } );
46
54
 
47
- const eIndicationsPopover = isExperimentActive( 'e_indications_popover' );
48
-
49
- if ( ! eIndicationsPopover ) {
50
- return <StyleIndicator variant={ variantType } aria-label={ label } />;
55
+ if ( ! isUsingIndicatorPopover() ) {
56
+ return (
57
+ <Tooltip title={ __( 'Style origin', 'elementor' ) } placement="top">
58
+ <StyleIndicator variant={ variantType } aria-label={ label } />
59
+ </Tooltip>
60
+ );
51
61
  }
52
62
 
53
- const toggleOpen = () => setOpen( ( prev ) => ! prev );
54
-
55
63
  return (
56
- <Infotip
57
- placement="top"
58
- content={
59
- <StyleIndicatorInfotip inheritanceChain={ inheritanceChain } path={ finalPath } propType={ propType } />
60
- }
61
- open={ open }
62
- onClose={ () => setOpen( false ) }
63
- trigger="manual"
64
+ <StyleIndicatorInfotip
65
+ inheritanceChain={ inheritanceChain }
66
+ path={ finalPath }
67
+ propType={ propType }
68
+ label={ label }
64
69
  >
65
- <IconButton onClick={ toggleOpen } aria-label={ label }>
66
- <StyleIndicator variant={ variantType } />
67
- </IconButton>
68
- </Infotip>
70
+ <StyleIndicator variant={ variantType } />
71
+ </StyleIndicatorInfotip>
69
72
  );
70
73
  };
71
74