@elementor/editor-editing-panel 1.45.0 → 1.46.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 (42) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/dist/index.d.mts +11 -4
  3. package/dist/index.d.ts +11 -4
  4. package/dist/index.js +702 -688
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +587 -573
  7. package/dist/index.mjs.map +1 -1
  8. package/package.json +14 -13
  9. package/src/components/css-classes/css-class-menu.tsx +6 -8
  10. package/src/components/css-classes/css-class-selector.tsx +17 -11
  11. package/src/components/settings-tab.tsx +25 -2
  12. package/src/components/style-indicator.tsx +19 -15
  13. package/src/components/style-sections/border-section/border-field.tsx +4 -6
  14. package/src/components/style-sections/effects-section/effects-section.tsx +6 -0
  15. package/src/components/style-sections/layout-section/flex-order-field.tsx +1 -3
  16. package/src/components/style-sections/layout-section/flex-size-field.tsx +7 -10
  17. package/src/components/style-sections/layout-section/layout-section.tsx +2 -2
  18. package/src/components/style-sections/layout-section/opacity-control-field.tsx +25 -0
  19. package/src/components/style-sections/layout-section/utils/rotated-icon.tsx +1 -1
  20. package/src/components/style-sections/position-section/position-section.tsx +6 -6
  21. package/src/components/style-sections/size-section/object-position-field.tsx +2 -24
  22. package/src/components/style-sections/size-section/size-section.tsx +1 -1
  23. package/src/components/style-sections/typography-section/text-stroke-field.tsx +4 -6
  24. package/src/components/style-sections/typography-section/typography-section.tsx +4 -2
  25. package/src/controls-registry/controls-registry.tsx +30 -10
  26. package/src/controls-registry/styles-field.tsx +1 -3
  27. package/src/dynamics/components/dynamic-selection-control.tsx +10 -18
  28. package/src/dynamics/components/dynamic-selection.tsx +58 -77
  29. package/src/dynamics/hooks/use-prop-dynamic-action.tsx +1 -1
  30. package/src/hooks/use-styles-field.ts +9 -3
  31. package/src/hooks/use-styles-fields.ts +4 -4
  32. package/src/index.ts +1 -0
  33. package/src/popover-action.tsx +3 -5
  34. package/src/provider-colors-registry.ts +20 -0
  35. package/src/styles-inheritance/components/infotip/label-chip.tsx +4 -5
  36. package/src/styles-inheritance/components/styles-inheritance-indicator.tsx +32 -40
  37. package/src/styles-inheritance/components/styles-inheritance-infotip.tsx +1 -5
  38. package/src/styles-inheritance/components/styles-inheritance-section-indicators.tsx +29 -44
  39. package/src/styles-inheritance/hooks/use-normalized-inheritance-chain-items.tsx +1 -17
  40. package/src/styles-inheritance/types.ts +0 -2
  41. package/src/styles-inheritance/utils.ts +17 -1
  42. package/src/utils/get-styles-provider-color.ts +28 -0
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { ControlFormLabel, useBoundProp } from '@elementor/editor-controls';
3
3
  import type { Control, ControlsSection } from '@elementor/editor-elements';
4
- import { PopoverHeader } from '@elementor/editor-ui';
4
+ import { PopoverHeader, PopoverScrollableContent } from '@elementor/editor-ui';
5
5
  import { DatabaseIcon, SettingsIcon, XIcon } from '@elementor/icons';
6
6
  import {
7
7
  bindPopover,
@@ -10,7 +10,6 @@ import {
10
10
  Divider,
11
11
  Grid,
12
12
  IconButton,
13
- Paper,
14
13
  Popover,
15
14
  Stack,
16
15
  Tab,
@@ -81,12 +80,7 @@ export const DynamicSelectionControl = () => {
81
80
  { ...bindPopover( selectionPopoverState ) }
82
81
  >
83
82
  <Stack>
84
- <PopoverHeader
85
- title={ __( 'Dynamic tags', 'elementor' ) }
86
- onClose={ selectionPopoverState.close }
87
- icon={ <DatabaseIcon fontSize={ SIZE } /> }
88
- />
89
- <DynamicSelection onSelect={ selectionPopoverState.close } />
83
+ <DynamicSelection close={ selectionPopoverState.close } />
90
84
  </Stack>
91
85
  </Popover>
92
86
  </Box>
@@ -113,14 +107,12 @@ export const DynamicSettingsPopover = ( { dynamicTag }: { dynamicTag: DynamicTag
113
107
  anchorOrigin={ { vertical: 'bottom', horizontal: 'center' } }
114
108
  { ...bindPopover( popupState ) }
115
109
  >
116
- <Paper component={ Stack } sx={ { minHeight: '300px', width: '220px' } }>
117
- <PopoverHeader
118
- title={ dynamicTag.label }
119
- onClose={ popupState.close }
120
- icon={ <DatabaseIcon fontSize={ SIZE } /> }
121
- />
122
- <DynamicSettings controls={ dynamicTag.atomic_controls } />
123
- </Paper>
110
+ <PopoverHeader
111
+ title={ dynamicTag.label }
112
+ onClose={ popupState.close }
113
+ icon={ <DatabaseIcon fontSize={ SIZE } /> }
114
+ />
115
+ <DynamicSettings controls={ dynamicTag.atomic_controls } />
124
116
  </Popover>
125
117
  </>
126
118
  );
@@ -136,7 +128,7 @@ const DynamicSettings = ( { controls }: { controls: DynamicTag[ 'atomic_controls
136
128
  }
137
129
 
138
130
  return (
139
- <>
131
+ <PopoverScrollableContent>
140
132
  <Tabs size="small" variant="fullWidth" { ...getTabsProps() }>
141
133
  { tabs.map( ( { value }, index ) => (
142
134
  <Tab key={ index } label={ value.label } sx={ { px: 1, py: 0.5 } } { ...getTabProps( index ) } />
@@ -158,7 +150,7 @@ const DynamicSettings = ( { controls }: { controls: DynamicTag[ 'atomic_controls
158
150
  </TabPanel>
159
151
  );
160
152
  } ) }
161
- </>
153
+ </PopoverScrollableContent>
162
154
  );
163
155
  };
164
156
 
@@ -1,19 +1,9 @@
1
- import * as React from 'react';
2
1
  import { Fragment, useState } from 'react';
2
+ import * as React from 'react';
3
3
  import { useBoundProp } from '@elementor/editor-controls';
4
- import { DatabaseIcon, SearchIcon } from '@elementor/icons';
5
- import {
6
- Box,
7
- Divider,
8
- InputAdornment,
9
- Link,
10
- MenuItem,
11
- MenuList,
12
- MenuSubheader,
13
- Stack,
14
- TextField,
15
- Typography,
16
- } from '@elementor/ui';
4
+ import { PopoverHeader, PopoverMenuList, PopoverSearch } from '@elementor/editor-ui';
5
+ import { DatabaseIcon } from '@elementor/icons';
6
+ import { Box, Divider, Link, Stack, Typography, useTheme } from '@elementor/ui';
17
7
  import { __ } from '@wordpress/i18n';
18
8
 
19
9
  import { usePersistDynamicValue } from '../../hooks/use-persist-dynamic-value';
@@ -31,7 +21,7 @@ type OptionEntry = [ string, Option[] ];
31
21
  const SIZE = 'tiny';
32
22
 
33
23
  type DynamicSelectionProps = {
34
- onSelect?: () => void;
24
+ close: () => void;
35
25
  };
36
26
 
37
27
  type NoResultsProps = {
@@ -39,9 +29,10 @@ type NoResultsProps = {
39
29
  onClear?: () => void;
40
30
  };
41
31
 
42
- export const DynamicSelection = ( { onSelect }: DynamicSelectionProps ) => {
32
+ export const DynamicSelection = ( { close: closePopover }: DynamicSelectionProps ) => {
43
33
  const [ searchValue, setSearchValue ] = useState( '' );
44
34
  const { groups: dynamicGroups } = getAtomicDynamicTags() || {};
35
+ const theme = useTheme();
45
36
 
46
37
  const { value: anyValue } = useBoundProp();
47
38
  const { bind, value: dynamicValue, setValue } = useBoundProp( dynamicPropTypeUtil );
@@ -54,79 +45,69 @@ export const DynamicSelection = ( { onSelect }: DynamicSelectionProps ) => {
54
45
 
55
46
  const hasNoDynamicTags = ! options.length && ! searchValue.trim();
56
47
 
57
- const handleSearch = ( event: React.ChangeEvent< HTMLInputElement > ) => {
58
- setSearchValue( event.target.value );
48
+ const handleSearch = ( value: string ) => {
49
+ setSearchValue( value );
59
50
  };
60
51
 
61
- const handleSetDynamicTag = ( value: string, label: string ) => {
52
+ const handleSetDynamicTag = ( value: string ) => {
62
53
  if ( ! isCurrentValueDynamic ) {
63
54
  updatePropValueHistory( anyValue );
64
55
  }
65
56
 
66
- setValue( { name: value, settings: { label } } );
57
+ const selectedOption = options.flatMap( ( [ , items ] ) => items ).find( ( item ) => item.value === value );
58
+
59
+ setValue( { name: value, settings: { label: selectedOption?.label } } );
67
60
 
68
- onSelect?.();
61
+ closePopover();
69
62
  };
70
63
 
64
+ const virtualizedItems = options.flatMap( ( [ category, items ] ) => [
65
+ {
66
+ type: 'category' as const,
67
+ value: category,
68
+ label: dynamicGroups?.[ category ]?.title || category,
69
+ },
70
+ ...items.map( ( item ) => ( {
71
+ type: 'item' as const,
72
+ value: item.value,
73
+ label: item.label,
74
+ } ) ),
75
+ ] );
76
+
71
77
  return (
72
- <Stack>
73
- { hasNoDynamicTags ? (
74
- <NoDynamicTags />
75
- ) : (
76
- <Fragment>
77
- <Box px={ 1.5 } pb={ 1 }>
78
- <TextField
79
- fullWidth
80
- size={ SIZE }
78
+ <>
79
+ <PopoverHeader
80
+ title={ __( 'Dynamic tags', 'elementor' ) }
81
+ onClose={ closePopover }
82
+ icon={ <DatabaseIcon fontSize={ SIZE } /> }
83
+ />
84
+ <Stack>
85
+ { hasNoDynamicTags ? (
86
+ <NoDynamicTags />
87
+ ) : (
88
+ <Fragment>
89
+ <PopoverSearch
81
90
  value={ searchValue }
82
- onChange={ handleSearch }
91
+ onSearch={ handleSearch }
83
92
  placeholder={ __( 'Search dynamic tags…', 'elementor' ) }
84
- InputProps={ {
85
- startAdornment: (
86
- <InputAdornment position="start">
87
- <SearchIcon fontSize={ SIZE } />
88
- </InputAdornment>
89
- ),
90
- } }
91
93
  />
92
- </Box>
93
- <Divider />
94
- <Box sx={ { overflowY: 'auto', height: 260, width: 220 } }>
95
- { options.length > 0 ? (
96
- <MenuList role="listbox" tabIndex={ 0 }>
97
- { options.map( ( [ category, items ], index ) => (
98
- <Fragment key={ index }>
99
- <MenuSubheader
100
- sx={ { px: 1.5, typography: 'caption', color: 'text.tertiary' } }
101
- >
102
- { dynamicGroups?.[ category ]?.title || category }
103
- </MenuSubheader>
104
- { items.map( ( { value, label: tagLabel } ) => {
105
- const isSelected = isCurrentValueDynamic && value === dynamicValue?.name;
106
-
107
- return (
108
- <MenuItem
109
- key={ value }
110
- selected={ isSelected }
111
- // eslint-disable-next-line jsx-a11y/no-autofocus
112
- autoFocus={ isSelected }
113
- sx={ { px: 3.5, typography: 'caption' } }
114
- onClick={ () => handleSetDynamicTag( value, tagLabel ) }
115
- >
116
- { tagLabel }
117
- </MenuItem>
118
- );
119
- } ) }
120
- </Fragment>
121
- ) ) }
122
- </MenuList>
123
- ) : (
124
- <NoResults searchValue={ searchValue } onClear={ () => setSearchValue( '' ) } />
125
- ) }
126
- </Box>
127
- </Fragment>
128
- ) }
129
- </Stack>
94
+ <Divider />
95
+ <PopoverMenuList
96
+ items={ virtualizedItems }
97
+ onSelect={ handleSetDynamicTag }
98
+ onClose={ closePopover }
99
+ selectedValue={ dynamicValue?.name }
100
+ itemStyle={ ( item ) =>
101
+ item.type === 'item' ? { paddingInlineStart: theme.spacing( 3.5 ) } : {}
102
+ }
103
+ noResultsComponent={
104
+ <NoResults searchValue={ searchValue } onClear={ () => setSearchValue( '' ) } />
105
+ }
106
+ />
107
+ </Fragment>
108
+ ) }
109
+ </Stack>
110
+ </>
130
111
  );
131
112
  };
132
113
 
@@ -173,7 +154,7 @@ const NoDynamicTags = () => (
173
154
  { __( 'Streamline your workflow with dynamic tags', 'elementor' ) }
174
155
  </Typography>
175
156
  <Typography align="center" variant="caption">
176
- { __( 'You’ll need Elementor Pro to use this feature.', 'elementor' ) }
157
+ { __( "You'll need Elementor Pro to use this feature.", 'elementor' ) }
177
158
  </Typography>
178
159
  </Stack>
179
160
  </Box>
@@ -16,6 +16,6 @@ export const usePropDynamicAction = (): PopoverActionProps => {
16
16
  visible,
17
17
  icon: DatabaseIcon,
18
18
  title: __( 'Dynamic tags', 'elementor' ),
19
- popoverContent: ( { closePopover } ) => <DynamicSelection onSelect={ closePopover } />,
19
+ content: ( { close } ) => <DynamicSelection close={ close } />,
20
20
  };
21
21
  };
@@ -2,8 +2,14 @@ import type { PropKey, PropValue } from '@elementor/editor-props';
2
2
 
3
3
  import { useStylesFields } from './use-styles-fields';
4
4
 
5
- export function useStylesField< T extends PropValue >( propName: PropKey ): [ T | null, ( newValue: T ) => void ] {
6
- const [ values, setValues ] = useStylesFields< { [ k: typeof propName ]: T } >( [ propName ] );
5
+ export function useStylesField< T extends PropValue >(
6
+ propName: PropKey
7
+ ): {
8
+ value: T;
9
+ setValue: ( newValue: T ) => void;
10
+ canEdit?: boolean;
11
+ } {
12
+ const { values, setValues, canEdit } = useStylesFields< { [ k: typeof propName ]: T } >( [ propName ] );
7
13
 
8
14
  const value = values?.[ propName ] ?? null;
9
15
 
@@ -13,5 +19,5 @@ export function useStylesField< T extends PropValue >( propName: PropKey ): [ T
13
19
  } );
14
20
  };
15
21
 
16
- return [ value, setValue ];
22
+ return { value: value as T, setValue, canEdit };
17
23
  }
@@ -21,7 +21,7 @@ import { useStylesRerender } from './use-styles-rerender';
21
21
 
22
22
  export function useStylesFields< T extends Props >( propNames: ( keyof T & string )[] ) {
23
23
  const { element } = useElement();
24
- const { id, meta, provider } = useStyle();
24
+ const { id, meta, provider, canEdit } = useStyle();
25
25
  const classesProp = useClassesProp();
26
26
 
27
27
  const undoableUpdateStyle = useUndoableUpdateStyle();
@@ -29,7 +29,7 @@ export function useStylesFields< T extends Props >( propNames: ( keyof T & strin
29
29
 
30
30
  useStylesRerender();
31
31
 
32
- const value = getProps< T >( {
32
+ const values = getProps< T >( {
33
33
  elementId: element.id,
34
34
  styleId: id,
35
35
  provider,
@@ -37,7 +37,7 @@ export function useStylesFields< T extends Props >( propNames: ( keyof T & strin
37
37
  propNames,
38
38
  } );
39
39
 
40
- const setValue = ( props: T ) => {
40
+ const setValues = ( props: T ) => {
41
41
  if ( id === null ) {
42
42
  undoableCreateElementStyle( {
43
43
  elementId: element.id,
@@ -58,7 +58,7 @@ export function useStylesFields< T extends Props >( propNames: ( keyof T & strin
58
58
  } );
59
59
  };
60
60
 
61
- return [ value, setValue ] as const;
61
+ return { values, setValues, canEdit };
62
62
  }
63
63
 
64
64
  type GetPropsArgs = {
package/src/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { useBoundProp } from '@elementor/editor-controls';
2
2
  export type { PopoverActionProps } from './popover-action';
3
3
  export { registerControlReplacement } from './control-replacement';
4
+ export { registerStyleProviderToColors } from './provider-colors-registry';
4
5
  export { injectIntoClassSelectorActions } from './components/css-classes/css-class-selector';
5
6
  export { usePanelActions, usePanelStatus } from './panel';
6
7
  export { type ValidationResult, type ValidationEvent } from './components/creatable-autocomplete';
@@ -1,6 +1,5 @@
1
1
  import * as React from 'react';
2
2
  import { type ComponentType, type ElementType as ReactElementType, useId } from 'react';
3
- import { PopoverHeader } from '@elementor/editor-ui';
4
3
  import { bindPopover, bindToggle, IconButton, Popover, Tooltip, usePopupState } from '@elementor/ui';
5
4
 
6
5
  const SIZE = 'tiny';
@@ -9,14 +8,14 @@ export type PopoverActionProps = {
9
8
  title: string;
10
9
  visible?: boolean;
11
10
  icon: ReactElementType;
12
- popoverContent: ComponentType< { closePopover: () => void } >;
11
+ content: ComponentType< { close: () => void } >;
13
12
  };
14
13
 
15
14
  export default function PopoverAction( {
16
15
  title,
17
16
  visible = true,
18
17
  icon: Icon,
19
- popoverContent: PopoverContent,
18
+ content: PopoverContent,
20
19
  }: PopoverActionProps ) {
21
20
  const id = useId();
22
21
  const popupState = usePopupState( {
@@ -44,8 +43,7 @@ export default function PopoverAction( {
44
43
  } }
45
44
  { ...bindPopover( popupState ) }
46
45
  >
47
- <PopoverHeader title={ title } onClose={ popupState.close } icon={ <Icon fontSize={ SIZE } /> } />
48
- <PopoverContent closePopover={ popupState.close } />
46
+ <PopoverContent close={ popupState.close } />
49
47
  </Popover>
50
48
  </>
51
49
  );
@@ -0,0 +1,20 @@
1
+ import { type ChipProps, type Theme } from '@elementor/ui';
2
+
3
+ type Colors = {
4
+ name: ChipProps[ 'color' ];
5
+ getThemeColor: ( ( theme: Theme ) => string ) | null;
6
+ };
7
+
8
+ const DEFAULT_COLORS: Colors = {
9
+ name: 'default',
10
+ getThemeColor: null,
11
+ };
12
+
13
+ const providerColorsRegistry = new Map< string, Colors >();
14
+
15
+ export const registerStyleProviderToColors = ( provider: string, colors: Colors ) => {
16
+ providerColorsRegistry.set( provider, colors );
17
+ };
18
+
19
+ export const getStyleProviderColors = ( provider: string ): Colors =>
20
+ providerColorsRegistry.get( provider ) ?? DEFAULT_COLORS;
@@ -4,17 +4,16 @@ import { InfoCircleIcon } from '@elementor/icons';
4
4
  import { Chip, type Theme, Tooltip } from '@elementor/ui';
5
5
  import { __ } from '@wordpress/i18n';
6
6
 
7
- import { type ChipColors } from '../../types';
7
+ import { getStylesProviderColorName } from '../../../utils/get-styles-provider-color';
8
8
 
9
9
  type Props = {
10
10
  displayLabel: string;
11
- provider?: string;
12
- chipColor: ChipColors;
11
+ provider: string;
13
12
  };
14
13
 
15
14
  const SIZE = 'tiny';
16
15
 
17
- export const LabelChip = ( { displayLabel, provider, chipColor }: Props ) => {
16
+ export const LabelChip = ( { displayLabel, provider }: Props ) => {
18
17
  const isBaseStyle = provider === ELEMENTS_BASE_STYLES_PROVIDER_KEY;
19
18
 
20
19
  const chipIcon = isBaseStyle ? (
@@ -27,7 +26,7 @@ export const LabelChip = ( { displayLabel, provider, chipColor }: Props ) => {
27
26
  <Chip
28
27
  label={ displayLabel }
29
28
  size={ SIZE }
30
- color={ chipColor }
29
+ color={ getStylesProviderColorName( provider ) }
31
30
  variant="standard"
32
31
  state="enabled"
33
32
  icon={ chipIcon }
@@ -1,7 +1,8 @@
1
1
  import * as React from 'react';
2
+ import { type ComponentProps } from 'react';
2
3
  import { useBoundProp } from '@elementor/editor-controls';
3
- import { isEmpty } from '@elementor/editor-props';
4
- import { ELEMENTS_BASE_STYLES_PROVIDER_KEY, isElementsStylesProvider } from '@elementor/editor-styles-repository';
4
+ import { isEmpty, type PropType } from '@elementor/editor-props';
5
+ import { ELEMENTS_BASE_STYLES_PROVIDER_KEY } from '@elementor/editor-styles-repository';
5
6
  import { isExperimentActive } from '@elementor/editor-v1-adapters';
6
7
  import { Tooltip } from '@elementor/ui';
7
8
  import { __ } from '@wordpress/i18n';
@@ -10,12 +11,14 @@ import { StyleIndicator } from '../../components/style-indicator';
10
11
  import { useStyle } from '../../contexts/style-context';
11
12
  import { useStylesInheritanceChain } from '../../contexts/styles-inheritance-context';
12
13
  import { EXPERIMENTAL_FEATURES } from '../../sync/experiments-flags';
14
+ import { getStylesProviderThemeColor } from '../../utils/get-styles-provider-color';
13
15
  import { isUsingIndicatorPopover } from '../consts';
16
+ import { type SnapshotPropValue } from '../types';
17
+ import { getValueFromInheritanceChain } from '../utils';
14
18
  import { StylesInheritanceInfotip } from './styles-inheritance-infotip';
15
19
 
16
20
  export const StylesInheritanceIndicator = () => {
17
21
  const { path, propType } = useBoundProp();
18
- const { id: currentStyleId, provider: currentStyleProvider, meta: currentStyleMeta } = useStyle();
19
22
 
20
23
  const isUsingNestedProps = isExperimentActive( EXPERIMENTAL_FEATURES.V_3_30 );
21
24
 
@@ -27,17 +30,21 @@ export const StylesInheritanceIndicator = () => {
27
30
  return null;
28
31
  }
29
32
 
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
- );
33
+ return <Indicator inheritanceChain={ inheritanceChain } path={ finalPath } propType={ propType } />;
34
+ };
35
+
36
+ type IndicatorProps = {
37
+ inheritanceChain: SnapshotPropValue[];
38
+ path: string[];
39
+ propType: PropType;
40
+ };
41
+
42
+ const Indicator = ( { inheritanceChain, path, propType }: IndicatorProps ) => {
43
+ const { id: currentStyleId, provider: currentStyleProvider, meta: currentStyleMeta } = useStyle();
44
+
45
+ const currentItem = currentStyleId
46
+ ? getValueFromInheritanceChain( inheritanceChain, currentStyleId, currentStyleMeta )
47
+ : null;
41
48
 
42
49
  const hasValue = ! isEmpty( currentItem?.value );
43
50
 
@@ -50,12 +57,19 @@ export const StylesInheritanceIndicator = () => {
50
57
  const isFinalValue = currentItem === actualStyle;
51
58
 
52
59
  const label = getLabel( { isFinalValue, hasValue } );
53
- const variantType = getVariant( { isFinalValue, hasValue, currentStyleProvider } );
60
+
61
+ const styleIndicatorProps: ComponentProps< typeof StyleIndicator > = {
62
+ getColor:
63
+ isFinalValue && currentStyleProvider
64
+ ? getStylesProviderThemeColor( currentStyleProvider.getKey() )
65
+ : undefined,
66
+ isOverridden: hasValue && ! isFinalValue ? true : undefined,
67
+ };
54
68
 
55
69
  if ( ! isUsingIndicatorPopover() ) {
56
70
  return (
57
71
  <Tooltip title={ __( 'Style origin', 'elementor' ) } placement="top">
58
- <StyleIndicator variant={ variantType } aria-label={ label } />
72
+ <StyleIndicator { ...styleIndicatorProps } aria-label={ label } />
59
73
  </Tooltip>
60
74
  );
61
75
  }
@@ -63,11 +77,11 @@ export const StylesInheritanceIndicator = () => {
63
77
  return (
64
78
  <StylesInheritanceInfotip
65
79
  inheritanceChain={ inheritanceChain }
66
- path={ finalPath }
80
+ path={ path }
67
81
  propType={ propType }
68
82
  label={ label }
69
83
  >
70
- <StyleIndicator variant={ variantType } />
84
+ <StyleIndicator { ...styleIndicatorProps } />
71
85
  </StylesInheritanceInfotip>
72
86
  );
73
87
  };
@@ -83,25 +97,3 @@ const getLabel = ( { isFinalValue, hasValue }: { isFinalValue: boolean; hasValue
83
97
 
84
98
  return __( 'This has value from another style', 'elementor' );
85
99
  };
86
-
87
- const getVariant = ( {
88
- isFinalValue,
89
- hasValue,
90
- currentStyleProvider,
91
- }: {
92
- isFinalValue: boolean;
93
- hasValue: boolean;
94
- currentStyleProvider: object | null;
95
- } ): 'local' | 'global' | 'overridden' | undefined => {
96
- if ( isFinalValue ) {
97
- return isElementsStylesProvider( ( currentStyleProvider as { getKey: () => string } )?.getKey?.() )
98
- ? 'local'
99
- : 'global';
100
- }
101
-
102
- if ( hasValue ) {
103
- return 'overridden';
104
- }
105
-
106
- return undefined;
107
- };
@@ -105,11 +105,7 @@ export const StylesInheritanceInfotip = ( { inheritanceChain, propType, path, la
105
105
  >
106
106
  <Box display="flex" gap={ 0.5 } sx={ { flexWrap: 'wrap', width: '100%' } }>
107
107
  <BreakpointIcon breakpoint={ item.breakpoint } />
108
- <LabelChip
109
- displayLabel={ item.displayLabel }
110
- provider={ item.provider }
111
- chipColor={ item.chipColor }
112
- />
108
+ <LabelChip displayLabel={ item.displayLabel } provider={ item.provider } />
113
109
  <ValueComponent index={ index } value={ item.value } />
114
110
  </Box>
115
111
  <ActionIcons />
@@ -1,58 +1,54 @@
1
1
  import * as React from 'react';
2
2
  import { type PropKey } from '@elementor/editor-props';
3
3
  import { type StyleDefinitionVariant } from '@elementor/editor-styles';
4
- import { ELEMENTS_BASE_STYLES_PROVIDER_KEY, isElementsStylesProvider } from '@elementor/editor-styles-repository';
4
+ import { isElementsStylesProvider } from '@elementor/editor-styles-repository';
5
5
  import { Stack, Tooltip } from '@elementor/ui';
6
6
  import { __ } from '@wordpress/i18n';
7
7
 
8
8
  import { StyleIndicator } from '../../components/style-indicator';
9
9
  import { useStyle } from '../../contexts/style-context';
10
10
  import { useStylesInheritanceSnapshot } from '../../contexts/styles-inheritance-context';
11
+ import { getStylesProviderThemeColor } from '../../utils/get-styles-provider-color';
11
12
  import { type SnapshotPropValue } from '../types';
12
-
13
13
  type Props = {
14
14
  fields: PropKey[];
15
15
  };
16
16
 
17
- type Indicators = {
18
- global?: true;
19
- local?: true;
20
- overridden?: true;
21
- };
22
-
23
- const orderedVariants = [ 'global', 'local', 'overridden' ] as ( keyof Indicators )[];
24
-
25
17
  export const StylesInheritanceSectionIndicators = ( { fields }: Props ) => {
26
- const { id, meta } = useStyle();
18
+ const { id, meta, provider } = useStyle();
27
19
  const snapshot = useStylesInheritanceSnapshot();
28
20
 
29
21
  const snapshotFields = Object.fromEntries(
30
22
  Object.entries( snapshot ?? {} ).filter( ( [ key ] ) => fields.includes( key as PropKey ) )
31
23
  );
32
24
 
33
- const indicators = getIndicators( snapshotFields, id ?? '', meta );
25
+ const { hasValues, hasOverrides } = getIndicators( snapshotFields, id ?? '', meta );
34
26
 
35
- if ( Object.values( indicators ).filter( Boolean ).length === 0 ) {
27
+ if ( ! hasValues && ! hasOverrides ) {
36
28
  return null;
37
29
  }
38
30
 
39
- const hasActualValues = __( 'Has effective styles', 'elementor' );
40
- const hasOverriddenValues = __( 'Has overridden styles', 'elementor' );
31
+ const hasValueLabel = __( 'Has effective styles', 'elementor' );
32
+ const hasOverridesLabel = __( 'Has overridden styles', 'elementor' );
41
33
 
42
34
  return (
43
35
  <Tooltip title={ __( 'Has styles', 'elementor' ) } placement="top">
44
36
  <Stack direction="row" sx={ { '& > *': { marginInlineStart: -0.25 } } } role="list">
45
- { orderedVariants.map(
46
- ( variant ) =>
47
- indicators[ variant ] && (
48
- <StyleIndicator
49
- key={ variant }
50
- variant={ variant }
51
- data-variant={ variant }
52
- role="listitem"
53
- aria-label={ variant === 'overridden' ? hasOverriddenValues : hasActualValues }
54
- />
55
- )
37
+ { hasValues && provider && (
38
+ <StyleIndicator
39
+ getColor={ getStylesProviderThemeColor( provider.getKey() ) }
40
+ data-variant={ isElementsStylesProvider( provider.getKey() ) ? 'local' : 'global' }
41
+ role="listitem"
42
+ aria-label={ hasValueLabel }
43
+ />
44
+ ) }
45
+ { hasOverrides && (
46
+ <StyleIndicator
47
+ isOverridden
48
+ data-variant="overridden"
49
+ role="listitem"
50
+ aria-label={ hasOverridesLabel }
51
+ />
56
52
  ) }
57
53
  </Stack>
58
54
  </Tooltip>
@@ -63,8 +59,9 @@ function getIndicators(
63
59
  snapshotFields: Record< PropKey, SnapshotPropValue[] >,
64
60
  styleId: string,
65
61
  meta: StyleDefinitionVariant[ 'meta' ]
66
- ): Indicators {
67
- const indicators: Indicators = {};
62
+ ): { hasValues: boolean; hasOverrides: boolean } {
63
+ let hasValues = false;
64
+ let hasOverrides = false;
68
65
 
69
66
  Object.values( snapshotFields ).forEach( ( inheritanceChain ) => {
70
67
  const currentStyle = getCurrentStyleFromChain( inheritanceChain, styleId, meta );
@@ -76,25 +73,13 @@ function getIndicators(
76
73
  const [ actualStyle ] = inheritanceChain;
77
74
 
78
75
  if ( currentStyle === actualStyle ) {
79
- const providerKey = actualStyle.provider ?? '';
80
-
81
- if ( isElementsStylesProvider( providerKey ) ) {
82
- indicators.local = true;
83
-
84
- return;
85
- }
86
-
87
- if ( providerKey !== ELEMENTS_BASE_STYLES_PROVIDER_KEY ) {
88
- indicators.global = true;
89
- }
90
-
91
- return;
76
+ hasValues = true;
77
+ } else {
78
+ hasOverrides = true;
92
79
  }
93
-
94
- indicators.overridden = true;
95
80
  } );
96
81
 
97
- return indicators;
82
+ return { hasValues, hasOverrides };
98
83
  }
99
84
 
100
85
  function getCurrentStyleFromChain(