@elementor/editor-editing-panel 3.33.0-99 → 3.34.2

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 (69) hide show
  1. package/dist/index.d.mts +419 -88
  2. package/dist/index.d.ts +419 -88
  3. package/dist/index.js +3361 -2421
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +3299 -2347
  6. package/dist/index.mjs.map +1 -1
  7. package/package.json +22 -21
  8. package/src/apply-unapply-actions.ts +30 -0
  9. package/src/components/collapsible-content.tsx +1 -0
  10. package/src/components/css-classes/css-class-item.tsx +14 -4
  11. package/src/components/css-classes/css-class-menu.tsx +83 -11
  12. package/src/components/css-classes/css-class-selector.tsx +22 -1
  13. package/src/components/css-classes/use-apply-and-unapply-class.ts +4 -13
  14. package/src/components/custom-css-indicator.tsx +68 -1
  15. package/src/components/editing-panel-tabs.tsx +13 -2
  16. package/src/components/interactions-tab.tsx +15 -0
  17. package/src/components/section-content.tsx +3 -2
  18. package/src/components/section.tsx +2 -1
  19. package/src/components/settings-control.tsx +79 -0
  20. package/src/components/settings-tab.tsx +16 -46
  21. package/src/components/style-sections/border-section/border-section.tsx +6 -4
  22. package/src/components/style-sections/effects-section/blend-mode-field.tsx +44 -0
  23. package/src/components/style-sections/effects-section/effects-section.tsx +4 -1
  24. package/src/components/style-sections/layout-section/flex-size-field.tsx +10 -8
  25. package/src/components/style-sections/typography-section/font-family-field.tsx +5 -1
  26. package/src/components/style-sections/typography-section/font-size-field.tsx +1 -1
  27. package/src/components/style-sections/typography-section/letter-spacing-field.tsx +1 -1
  28. package/src/components/style-sections/typography-section/text-color-field.tsx +1 -1
  29. package/src/components/style-sections/typography-section/word-spacing-field.tsx +1 -1
  30. package/src/components/style-tab-section.tsx +2 -2
  31. package/src/components/style-tab.tsx +12 -17
  32. package/src/components/styles-field-layout.tsx +8 -1
  33. package/src/contexts/interaction-context.tsx +0 -0
  34. package/src/controls-registry/conditional-field.tsx +1 -1
  35. package/src/controls-registry/control-type-container.tsx +17 -5
  36. package/src/controls-registry/controls-registry.tsx +18 -5
  37. package/src/controls-registry/element-controls/get-element-by-type.ts +21 -0
  38. package/src/controls-registry/element-controls/registry.ts +16 -0
  39. package/src/controls-registry/element-controls/tabs-control/tabs-control.tsx +229 -0
  40. package/src/controls-registry/element-controls/tabs-control/use-actions.ts +248 -0
  41. package/src/controls-registry/settings-field.tsx +54 -10
  42. package/src/controls-registry/styles-field.tsx +2 -9
  43. package/src/dynamics/components/dynamic-conditional-control.tsx +62 -0
  44. package/src/dynamics/components/dynamic-selection-control.tsx +81 -25
  45. package/src/dynamics/components/dynamic-selection.tsx +3 -3
  46. package/src/dynamics/dynamic-control.tsx +10 -1
  47. package/src/dynamics/hooks/use-prop-dynamic-tags.ts +24 -6
  48. package/src/field-indicators-registry.ts +37 -0
  49. package/src/hooks/use-computed-style.ts +1 -4
  50. package/src/index.ts +16 -3
  51. package/src/init.ts +7 -0
  52. package/src/reset-style-props.tsx +21 -4
  53. package/src/styles-inheritance/components/infotip/value-component.tsx +2 -0
  54. package/src/styles-inheritance/components/styles-inheritance-indicator.tsx +1 -13
  55. package/src/styles-inheritance/components/styles-inheritance-infotip.tsx +5 -1
  56. package/src/styles-inheritance/hooks/use-normalized-inheritance-chain-items.tsx +18 -2
  57. package/src/styles-inheritance/init-styles-inheritance-transformers.ts +25 -4
  58. package/src/styles-inheritance/init.ts +9 -0
  59. package/src/styles-inheritance/transformers/{background-overlay-transformer.tsx → array-transformer.tsx} +2 -2
  60. package/src/styles-inheritance/transformers/background-color-overlay-transformer.tsx +0 -6
  61. package/src/styles-inheritance/transformers/box-shadow-transformer.tsx +32 -0
  62. package/src/styles-inheritance/transformers/color-transformer.tsx +32 -0
  63. package/src/styles-inheritance/transformers/repeater-to-items-transformer.tsx +27 -0
  64. package/src/utils/is-equal.ts +53 -0
  65. package/src/utils/prop-dependency-utils.ts +107 -19
  66. package/src/utils/tracking/subscribe.ts +7 -0
  67. package/src/components/custom-css-field.tsx +0 -20
  68. package/src/components/custom-css.tsx +0 -36
  69. package/src/components/style-sections/border-section/border-field.tsx +0 -54
@@ -33,6 +33,8 @@ import { DynamicSelection } from './dynamic-selection';
33
33
 
34
34
  const SIZE = 'tiny';
35
35
 
36
+ const tagsWithoutTabs = [ 'popup' ];
37
+
36
38
  export const DynamicSelectionControl = () => {
37
39
  const { setValue: setAnyValue } = useBoundProp();
38
40
  const { bind, value } = useBoundProp( dynamicPropTypeUtil );
@@ -83,7 +85,7 @@ export const DynamicSelectionControl = () => {
83
85
  } }
84
86
  { ...bindPopover( selectionPopoverState ) }
85
87
  >
86
- <PopoverBody>
88
+ <PopoverBody aria-label={ __( 'Dynamic tags', 'elementor' ) }>
87
89
  <DynamicSelection close={ selectionPopoverState.close } />
88
90
  </PopoverBody>
89
91
  </Popover>
@@ -102,7 +104,11 @@ export const DynamicSettingsPopover = ( { dynamicTag }: { dynamicTag: DynamicTag
102
104
 
103
105
  return (
104
106
  <>
105
- <IconButton size={ SIZE } { ...bindTrigger( popupState ) } aria-label={ __( 'Settings', 'elementor' ) }>
107
+ <IconButton
108
+ size={ SIZE }
109
+ { ...bindTrigger( popupState ) }
110
+ aria-label={ __( 'Dynamic settings', 'elementor' ) }
111
+ >
106
112
  <SettingsIcon fontSize={ SIZE } />
107
113
  </IconButton>
108
114
  <Popover
@@ -115,20 +121,20 @@ export const DynamicSettingsPopover = ( { dynamicTag }: { dynamicTag: DynamicTag
115
121
  } }
116
122
  { ...bindPopover( popupState ) }
117
123
  >
118
- <PopoverBody>
124
+ <PopoverBody aria-label={ __( 'Dynamic settings', 'elementor' ) }>
119
125
  <PopoverHeader
120
126
  title={ dynamicTag.label }
121
127
  onClose={ popupState.close }
122
128
  icon={ <DatabaseIcon fontSize={ SIZE } /> }
123
129
  />
124
- <DynamicSettings controls={ dynamicTag.atomic_controls } />
130
+ <DynamicSettings controls={ dynamicTag.atomic_controls } tagName={ dynamicTag.name } />
125
131
  </PopoverBody>
126
132
  </Popover>
127
133
  </>
128
134
  );
129
135
  };
130
136
 
131
- const DynamicSettings = ( { controls }: { controls: DynamicTag[ 'atomic_controls' ] } ) => {
137
+ const DynamicSettings = ( { controls, tagName }: { controls: DynamicTag[ 'atomic_controls' ]; tagName: string } ) => {
132
138
  const tabs = controls.filter( ( { type } ) => type === 'section' ) as ControlsSection[];
133
139
  const { getTabsProps, getTabProps, getTabPanelProps } = useTabs< number >( 0 );
134
140
 
@@ -137,15 +143,31 @@ const DynamicSettings = ( { controls }: { controls: DynamicTag[ 'atomic_controls
137
143
  return null;
138
144
  }
139
145
 
146
+ if ( tagsWithoutTabs.includes( tagName ) ) {
147
+ const singleTab = tabs[ 0 ];
148
+ return (
149
+ <>
150
+ <Divider />
151
+ <ControlsItemsStack items={ singleTab.value.items } />
152
+ </>
153
+ );
154
+ }
155
+
140
156
  return (
141
157
  <>
142
- <Tabs size="small" variant="fullWidth" { ...getTabsProps() }>
143
- { tabs.map( ( { value }, index ) => (
144
- <Tab key={ index } label={ value.label } sx={ { px: 1, py: 0.5 } } { ...getTabProps( index ) } />
145
- ) ) }
146
- </Tabs>
158
+ { tabs.length > 1 && (
159
+ <Tabs size="small" variant="fullWidth" { ...getTabsProps() }>
160
+ { tabs.map( ( { value }, index ) => (
161
+ <Tab
162
+ key={ index }
163
+ label={ value.label }
164
+ sx={ { px: 1, py: 0.5 } }
165
+ { ...getTabProps( index ) }
166
+ />
167
+ ) ) }
168
+ </Tabs>
169
+ ) }
147
170
  <Divider />
148
-
149
171
  { tabs.map( ( { value }, index ) => {
150
172
  return (
151
173
  <TabPanel
@@ -153,14 +175,7 @@ const DynamicSettings = ( { controls }: { controls: DynamicTag[ 'atomic_controls
153
175
  sx={ { flexGrow: 1, py: 0, overflowY: 'auto' } }
154
176
  { ...getTabPanelProps( index ) }
155
177
  >
156
- <Stack p={ 2 } gap={ 2 }>
157
- { value.items.map( ( item ) => {
158
- if ( item.type === 'control' ) {
159
- return <Control key={ item.value.bind } control={ item.value } />;
160
- }
161
- return null;
162
- } ) }
163
- </Stack>
178
+ <ControlsItemsStack items={ value.items } />
164
179
  </TabPanel>
165
180
  );
166
181
  } ) }
@@ -170,9 +185,21 @@ const DynamicSettings = ( { controls }: { controls: DynamicTag[ 'atomic_controls
170
185
 
171
186
  const LAYOUT_OVERRIDE_FIELDS = {
172
187
  separator: 'two-columns',
188
+ action: 'full',
189
+ off_canvas: 'full',
190
+ type: 'two-columns',
191
+ } as const;
192
+
193
+ const DYNAMIC_TAG_LAYOUT_OVERRIDES = {
194
+ select: 'full',
173
195
  } as const;
174
196
 
175
197
  const getLayout = ( control: Control[ 'value' ] ): ControlLayout => {
198
+ const dynamicOverride = DYNAMIC_TAG_LAYOUT_OVERRIDES[ control.type as keyof typeof DYNAMIC_TAG_LAYOUT_OVERRIDES ];
199
+ if ( dynamicOverride ) {
200
+ return dynamicOverride;
201
+ }
202
+
176
203
  return (
177
204
  LAYOUT_OVERRIDE_FIELDS[ control.bind as keyof typeof LAYOUT_OVERRIDE_FIELDS ] ??
178
205
  controlsRegistry.getLayout( control.type as ControlType )
@@ -186,22 +213,51 @@ const Control = ( { control }: { control: Control[ 'value' ] } ) => {
186
213
 
187
214
  const layout = getLayout( control );
188
215
 
216
+ const shouldDisablePortal = control.type === 'select';
217
+ const baseControlProps = shouldDisablePortal
218
+ ? {
219
+ ...control.props,
220
+ MenuProps: {
221
+ ...( control.props?.MenuProps ?? {} ),
222
+ disablePortal: true,
223
+ },
224
+ }
225
+ : { ...control.props };
226
+ const controlProps = {
227
+ ...baseControlProps,
228
+ ariaLabel: control.label,
229
+ } as typeof baseControlProps & { ariaLabel?: string };
230
+ const isSwitchControl = control.type === 'switch';
231
+ const layoutStyleProps =
232
+ layout === 'two-columns'
233
+ ? {
234
+ display: 'grid',
235
+ gridTemplateColumns: isSwitchControl ? 'minmax(0, 1fr) max-content' : '1fr 1fr',
236
+ }
237
+ : {};
238
+
189
239
  return (
190
240
  <DynamicControl bind={ control.bind }>
191
- <Grid
192
- container
193
- gap={ 0.75 }
194
- sx={ layout === 'two-columns' ? { display: 'grid', gridTemplateColumns: '1fr 1fr' } : {} }
195
- >
241
+ <Grid container gap={ 0.75 } sx={ layoutStyleProps }>
196
242
  { control.label ? (
197
243
  <Grid item xs={ 12 }>
198
244
  <ControlFormLabel>{ control.label }</ControlFormLabel>
199
245
  </Grid>
200
246
  ) : null }
201
247
  <Grid item xs={ 12 }>
202
- <BaseControl type={ control.type as ControlType } props={ control.props } />
248
+ <BaseControl type={ control.type as ControlType } props={ controlProps } />
203
249
  </Grid>
204
250
  </Grid>
205
251
  </DynamicControl>
206
252
  );
207
253
  };
254
+
255
+ function ControlsItemsStack( { items }: { items: ControlsSection[ 'value' ][ 'items' ] } ) {
256
+ return (
257
+ <Stack p={ 2 } gap={ 2 } sx={ { overflowY: 'auto' } }>
258
+ { items.map( ( item ) =>
259
+ item.type === 'control' ? <Control key={ item.value.bind } control={ item.value } /> : null
260
+ ) }
261
+ </Stack>
262
+ );
263
+ }
@@ -1,7 +1,7 @@
1
1
  import { Fragment, useState } from 'react';
2
2
  import * as React from 'react';
3
3
  import { useBoundProp } from '@elementor/editor-controls';
4
- import { PopoverHeader, PopoverMenuList, PopoverSearch } from '@elementor/editor-ui';
4
+ import { PopoverHeader, PopoverMenuList, SearchField } from '@elementor/editor-ui';
5
5
  import { DatabaseIcon } from '@elementor/icons';
6
6
  import { Divider, Link, Stack, Typography, useTheme } from '@elementor/ui';
7
7
  import { __ } from '@wordpress/i18n';
@@ -76,7 +76,7 @@ export const DynamicSelection = ( { close: closePopover }: DynamicSelectionProps
76
76
  ] );
77
77
 
78
78
  return (
79
- <PopoverBody>
79
+ <PopoverBody aria-label={ __( 'Dynamic tags', 'elementor' ) }>
80
80
  <PopoverHeader
81
81
  title={ __( 'Dynamic tags', 'elementor' ) }
82
82
  onClose={ closePopover }
@@ -86,7 +86,7 @@ export const DynamicSelection = ( { close: closePopover }: DynamicSelectionProps
86
86
  <NoDynamicTags />
87
87
  ) : (
88
88
  <Fragment>
89
- <PopoverSearch
89
+ <SearchField
90
90
  value={ searchValue }
91
91
  onSearch={ handleSearch }
92
92
  placeholder={ __( 'Search dynamic tags…', 'elementor' ) }
@@ -3,6 +3,7 @@ import { PropKeyProvider, PropProvider, type SetValue, useBoundProp } from '@ele
3
3
  import { type PropKey } from '@elementor/editor-props';
4
4
 
5
5
  import { createTopLevelObjectType } from '../controls-registry/create-top-level-object-type';
6
+ import { DynamicConditionalControl } from './components/dynamic-conditional-control';
6
7
  import { useDynamicTag } from './hooks/use-dynamic-tag';
7
8
  import { dynamicPropTypeUtil, type DynamicPropValue } from './utils';
8
9
 
@@ -39,7 +40,15 @@ export const DynamicControl = ( { bind, children }: DynamicControlProps ) => {
39
40
 
40
41
  return (
41
42
  <PropProvider propType={ propType } setValue={ setDynamicValue } value={ { [ bind ]: dynamicValue } }>
42
- <PropKeyProvider bind={ bind }>{ children }</PropKeyProvider>
43
+ <PropKeyProvider bind={ bind }>
44
+ <DynamicConditionalControl
45
+ propType={ dynamicPropType }
46
+ propsSchema={ dynamicTag.props_schema }
47
+ dynamicSettings={ settings }
48
+ >
49
+ { children }
50
+ </DynamicConditionalControl>
51
+ </PropKeyProvider>
43
52
  </PropProvider>
44
53
  );
45
54
  };
@@ -2,6 +2,7 @@ import { useMemo } from 'react';
2
2
  import { useBoundProp } from '@elementor/editor-controls';
3
3
 
4
4
  import { getAtomicDynamicTags } from '../sync/get-atomic-dynamic-tags';
5
+ import { type DynamicTag } from '../types';
5
6
  import { getDynamicPropType } from '../utils';
6
7
 
7
8
  export const usePropDynamicTags = () => {
@@ -15,21 +16,38 @@ export const usePropDynamicTags = () => {
15
16
  categories = propDynamicType?.settings.categories || [];
16
17
  }
17
18
 
18
- // eslint-disable-next-line react-compiler/react-compiler
19
19
  // eslint-disable-next-line react-hooks/exhaustive-deps
20
20
  return useMemo( () => getDynamicTagsByCategories( categories ), [ categories.join() ] );
21
21
  };
22
22
 
23
23
  const getDynamicTagsByCategories = ( categories: string[] ) => {
24
- const dynamicTags = getAtomicDynamicTags();
24
+ const { tags, groups } = getAtomicDynamicTags() || {};
25
25
 
26
- if ( ! categories.length || ! dynamicTags?.tags ) {
26
+ if ( ! categories.length || ! tags || ! groups ) {
27
27
  return [];
28
28
  }
29
29
 
30
30
  const _categories = new Set( categories );
31
31
 
32
- return Object.values( dynamicTags.tags ).filter( ( dynamicTag ) =>
33
- dynamicTag.categories.some( ( category ) => _categories.has( category ) )
34
- );
32
+ const dynamicTags: DynamicTag[] = [];
33
+ const groupedFilteredTags: Record< string, DynamicTag[] > = {};
34
+
35
+ for ( const tag of Object.values( tags ) ) {
36
+ if ( ! tag.categories.some( ( category ) => _categories.has( category ) ) ) {
37
+ continue;
38
+ }
39
+
40
+ if ( ! groupedFilteredTags[ tag.group ] ) {
41
+ groupedFilteredTags[ tag.group ] = [];
42
+ }
43
+ groupedFilteredTags[ tag.group ].push( tag );
44
+ }
45
+
46
+ for ( const group in groups ) {
47
+ if ( groupedFilteredTags[ group ] ) {
48
+ dynamicTags.push( ...groupedFilteredTags[ group ] );
49
+ }
50
+ }
51
+
52
+ return dynamicTags;
35
53
  };
@@ -0,0 +1,37 @@
1
+ import { type AdornmentComponent } from '@elementor/editor-controls';
2
+
3
+ type FieldType = 'settings' | 'styles';
4
+
5
+ type FieldIndicator = {
6
+ id: string;
7
+ indicator: AdornmentComponent;
8
+
9
+ // ordered from lowest to highest
10
+ priority: number;
11
+ };
12
+
13
+ const indicatorsRegistry: Record< FieldType, Map< string, FieldIndicator > > = {
14
+ settings: new Map(),
15
+ styles: new Map(),
16
+ };
17
+
18
+ const DEFAULT_PRIORITY = 10;
19
+
20
+ export const FIELD_TYPE = {
21
+ SETTINGS: 'settings',
22
+ STYLES: 'styles',
23
+ } satisfies Record< string, FieldType >;
24
+
25
+ export const registerFieldIndicator = ( {
26
+ fieldType,
27
+ id,
28
+ indicator,
29
+ priority = DEFAULT_PRIORITY,
30
+ }: FieldIndicator & { fieldType: FieldType } ) => {
31
+ indicatorsRegistry[ fieldType ].set( id, { id, indicator, priority } );
32
+ };
33
+
34
+ export const getFieldIndicators = ( fieldType: FieldType ): { id: string; Adornment: AdornmentComponent }[] =>
35
+ Array.from( indicatorsRegistry[ fieldType ].values() )
36
+ .sort( ( a, b ) => a.priority - b.priority )
37
+ .map( ( { id, indicator: Adornment } ) => ( { id, Adornment } ) );
@@ -1,7 +1,5 @@
1
1
  import { __privateUseListenTo as useListenTo, commandEndEvent, windowEvent } from '@elementor/editor-v1-adapters';
2
2
 
3
- import { type ExtendedWindow } from '../sync/types';
4
-
5
3
  export function useComputedStyle( elementId: string | null ) {
6
4
  return useListenTo(
7
5
  [
@@ -15,8 +13,7 @@ export function useComputedStyle( elementId: string | null ) {
15
13
  return null;
16
14
  }
17
15
 
18
- const extendedWindow: ExtendedWindow = window;
19
- const element = extendedWindow.elementor?.getContainer?.( elementId );
16
+ const element = window.elementor?.getContainer?.( elementId );
20
17
 
21
18
  if ( ! element?.view?.el ) {
22
19
  return null;
package/src/index.ts CHANGED
@@ -2,17 +2,30 @@ export { useBoundProp } from '@elementor/editor-controls';
2
2
  export { type ValidationEvent, type ValidationResult } from './components/creatable-autocomplete';
3
3
  export { injectIntoCssClassConvert } from './components/css-classes/css-class-convert-local';
4
4
  export { injectIntoClassSelectorActions } from './components/css-classes/css-class-selector';
5
+ export { CustomCssIndicator } from './components/custom-css-indicator';
5
6
  export { PopoverBody } from './components/popover-body';
6
7
  export { SectionContent } from './components/section-content';
7
- export { CustomCss } from './components/custom-css';
8
+ export { SettingsControl } from './components/settings-control';
9
+ export { StyleIndicator } from './components/style-indicator';
8
10
  export { useFontFamilies } from './components/style-sections/typography-section/hooks/use-font-families';
9
- export { useCustomCss } from './hooks/use-custom-css';
11
+ export { injectIntoStyleTab } from './components/style-tab';
12
+ export { StyleTabSection } from './components/style-tab-section';
13
+ export { useClassesProp } from './contexts/classes-prop-context';
14
+ export { useElement } from './contexts/element-context';
10
15
  export { useSectionWidth } from './contexts/section-context';
16
+ export { useStyle } from './contexts/style-context';
11
17
  export { registerControlReplacement } from './control-replacement';
12
18
  export { controlActionsMenu } from './controls-actions';
19
+ export { controlsRegistry } from './controls-registry/controls-registry';
20
+ export { StylesProviderCannotUpdatePropsError } from './errors';
21
+ export { useCustomCss } from './hooks/use-custom-css';
22
+ export { getSubtitle, getTitle, HISTORY_DEBOUNCE_WAIT } from './hooks/use-styles-fields';
23
+ export { useStylesRerender } from './hooks/use-styles-rerender';
13
24
  export { init } from './init';
14
25
  export { usePanelActions, usePanelStatus } from './panel';
15
26
  export type { PopoverActionProps } from './popover-action';
16
27
  export { registerStyleProviderToColors } from './provider-colors-registry';
17
28
  export { stylesInheritanceTransformersRegistry } from './styles-inheritance/styles-inheritance-transformers-registry';
18
- export { controlsRegistry } from './controls-registry/controls-registry';
29
+ export { registerFieldIndicator, FIELD_TYPE } from './field-indicators-registry';
30
+
31
+ export { doApplyClasses, doGetAppliedClasses, doUnapplyClass } from './apply-unapply-actions';
package/src/init.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  import { injectIntoLogic } from '@elementor/editor';
2
+ import { initElementsMcp } from '@elementor/editor-elements';
2
3
  import { __registerPanel as registerPanel } from '@elementor/editor-panels';
3
4
  import { blockCommand } from '@elementor/editor-v1-adapters';
4
5
 
5
6
  import { EditingPanelHooks } from './components/editing-panel-hooks';
7
+ import { registerElementControls } from './controls-registry/element-controls/registry';
6
8
  import { init as initDynamics } from './dynamics/init';
7
9
  import { panel } from './panel';
8
10
  import { initResetStyleProps } from './reset-style-props';
@@ -13,6 +15,8 @@ export function init() {
13
15
  registerPanel( panel );
14
16
  blockV1Panel();
15
17
 
18
+ initElementsMcp();
19
+
16
20
  injectIntoLogic( {
17
21
  id: 'editing-panel-hooks',
18
22
  component: EditingPanelHooks,
@@ -24,6 +28,9 @@ export function init() {
24
28
  // TODO: Move it from here once we have styles-inheritance package.
25
29
  initStylesInheritance();
26
30
 
31
+ // TODO: Move it from here once we have element-controls package.
32
+ registerElementControls();
33
+
27
34
  initResetStyleProps();
28
35
  }
29
36
 
@@ -4,6 +4,7 @@ import { __ } from '@wordpress/i18n';
4
4
 
5
5
  import { useIsStyle } from './contexts/style-context';
6
6
  import { controlActionsMenu } from './controls-actions';
7
+ import { isEqual } from './utils/is-equal';
7
8
 
8
9
  const { registerAction } = controlActionsMenu;
9
10
 
@@ -16,14 +17,30 @@ export function initResetStyleProps() {
16
17
 
17
18
  export function useResetStyleValueProps() {
18
19
  const isStyle = useIsStyle();
19
- const { value, setValue, path } = useBoundProp();
20
+ const { value, resetValue, propType } = useBoundProp();
21
+ const hasValue = value !== null && value !== undefined;
22
+ const hasInitial = propType.initial_value !== undefined && propType.initial_value !== null;
23
+ const isRequired = !! propType.settings?.required;
24
+ const shouldHide = !! propType.settings?.hide_reset;
20
25
 
21
- const isInRepeater = path?.some( ( key ) => ! isNaN( Number( key ) ) );
26
+ function calculateVisibility() {
27
+ if ( ! isStyle || ! hasValue || shouldHide ) {
28
+ return false;
29
+ }
30
+
31
+ if ( hasInitial ) {
32
+ return ! isEqual( value, propType.initial_value );
33
+ }
34
+
35
+ return ! isRequired;
36
+ }
37
+
38
+ const visible = calculateVisibility();
22
39
 
23
40
  return {
24
- visible: isStyle && value !== null && value !== undefined && ! isInRepeater,
41
+ visible,
25
42
  title: __( 'Clear', 'elementor' ),
26
43
  icon: BrushBigIcon,
27
- onClick: () => setValue( null ),
44
+ onClick: () => resetValue(),
28
45
  };
29
46
  }
@@ -18,6 +18,8 @@ export const ValueComponent = ( { index, value }: Props ) => {
18
18
  textOverflow: 'ellipsis',
19
19
  whiteSpace: 'nowrap',
20
20
  pl: 2.5,
21
+ minWidth: 0,
22
+ maxWidth: '100%',
21
23
  } }
22
24
  >
23
25
  { value }
@@ -12,9 +12,6 @@ import { getStylesProviderThemeColor } from '../../utils/get-styles-provider-col
12
12
  import { type SnapshotPropValue } from '../types';
13
13
  import { getValueFromInheritanceChain } from '../utils';
14
14
  import { StylesInheritanceInfotip } from './styles-inheritance-infotip';
15
-
16
- const disabledControls = [ 'box-shadow', 'background-overlay', 'filter', 'backdrop-filter', 'transform', 'transition' ];
17
-
18
15
  export const StylesInheritanceIndicator = ( {
19
16
  customContext,
20
17
  }: {
@@ -28,16 +25,7 @@ export const StylesInheritanceIndicator = ( {
28
25
  return null;
29
26
  }
30
27
 
31
- const isDisabled = path.some( ( pathItem ) => disabledControls.includes( pathItem ) );
32
-
33
- return (
34
- <Indicator
35
- inheritanceChain={ inheritanceChain }
36
- path={ path }
37
- propType={ propType }
38
- isDisabled={ isDisabled }
39
- />
40
- );
28
+ return <Indicator inheritanceChain={ inheritanceChain } path={ path } propType={ propType } />;
41
29
  };
42
30
 
43
31
  type IndicatorProps = {
@@ -122,7 +122,11 @@ export const StylesInheritanceInfotip = ( {
122
122
  item.displayLabel
123
123
  ) }
124
124
  >
125
- <Box display="flex" gap={ 0.5 } sx={ { flexWrap: 'wrap', width: '100%' } }>
125
+ <Box
126
+ display="flex"
127
+ gap={ 0.5 }
128
+ sx={ { flexWrap: 'wrap', width: '100%', alignItems: 'flex-start' } }
129
+ >
126
130
  <BreakpointIcon breakpoint={ item.breakpoint } />
127
131
  <LabelChip displayLabel={ item.displayLabel } provider={ item.provider } />
128
132
  <ValueComponent index={ index } value={ item.value } />
@@ -1,7 +1,12 @@
1
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
- import { type StyleDefinitionVariant } from '@elementor/editor-styles';
4
+ import {
5
+ isClassState,
6
+ isPseudoState,
7
+ type StyleDefinitionState,
8
+ type StyleDefinitionVariant,
9
+ } from '@elementor/editor-styles';
5
10
  import { ELEMENTS_BASE_STYLES_PROVIDER_KEY } from '@elementor/editor-styles-repository';
6
11
  import { __ } from '@wordpress/i18n';
7
12
 
@@ -65,7 +70,7 @@ export const normalizeInheritanceItem = async (
65
70
  style: { label, id },
66
71
  } = item;
67
72
 
68
- const displayLabel = `${ label }${ state ? ':' + state : '' }`;
73
+ const displayLabel = getLabel( { label, state } );
69
74
 
70
75
  return {
71
76
  id: id ? id + ( state ?? '' ) : index,
@@ -76,6 +81,17 @@ export const normalizeInheritanceItem = async (
76
81
  };
77
82
  };
78
83
 
84
+ function getLabel( { label, state }: { label: string; state: StyleDefinitionState } ) {
85
+ if ( isClassState( state ) ) {
86
+ return `${ label }.${ state }`;
87
+ }
88
+
89
+ if ( isPseudoState( state ) ) {
90
+ return `${ label }:${ state }`;
91
+ }
92
+
93
+ return label;
94
+ }
79
95
  const getTransformedValue = async (
80
96
  item: SnapshotPropValue,
81
97
  bind: PropKey,
@@ -2,10 +2,13 @@ import { createTransformer, styleTransformersRegistry } from '@elementor/editor-
2
2
 
3
3
  import { excludePropTypeTransformers } from './consts';
4
4
  import { stylesInheritanceTransformersRegistry } from './styles-inheritance-transformers-registry';
5
+ import { arrayTransformer } from './transformers/array-transformer';
5
6
  import { backgroundColorOverlayTransformer } from './transformers/background-color-overlay-transformer';
6
7
  import { backgroundGradientOverlayTransformer } from './transformers/background-gradient-overlay-transformer';
7
8
  import { backgroundImageOverlayTransformer } from './transformers/background-image-overlay-transformer';
8
- import { backgroundOverlayTransformer } from './transformers/background-overlay-transformer';
9
+ import { boxShadowTransformer } from './transformers/box-shadow-transformer';
10
+ import { colorTransformer } from './transformers/color-transformer';
11
+ import { createRepeaterToItemsTransformer } from './transformers/repeater-to-items-transformer';
9
12
 
10
13
  export function initStylesInheritanceTransformers() {
11
14
  const originalStyleTransformers = styleTransformersRegistry.all();
@@ -24,15 +27,33 @@ export function initStylesInheritanceTransformers() {
24
27
  } )
25
28
  );
26
29
 
27
- registerCustomTransformers();
30
+ registerCustomTransformers( originalStyleTransformers );
28
31
  }
29
32
 
30
- function registerCustomTransformers() {
33
+ function registerCustomTransformers( originalStyleTransformers: ReturnType< typeof styleTransformersRegistry.all > ) {
34
+ stylesInheritanceTransformersRegistry.register( 'color', colorTransformer );
31
35
  stylesInheritanceTransformersRegistry.register( 'background-color-overlay', backgroundColorOverlayTransformer );
32
36
  stylesInheritanceTransformersRegistry.register(
33
37
  'background-gradient-overlay',
34
38
  backgroundGradientOverlayTransformer
35
39
  );
36
40
  stylesInheritanceTransformersRegistry.register( 'background-image-overlay', backgroundImageOverlayTransformer );
37
- stylesInheritanceTransformersRegistry.register( 'background-overlay', backgroundOverlayTransformer );
41
+ stylesInheritanceTransformersRegistry.register( 'shadow', boxShadowTransformer );
42
+
43
+ stylesInheritanceTransformersRegistry.register(
44
+ 'filter',
45
+ createRepeaterToItemsTransformer( originalStyleTransformers.filter )
46
+ );
47
+ stylesInheritanceTransformersRegistry.register(
48
+ 'backdrop-filter',
49
+ createRepeaterToItemsTransformer( originalStyleTransformers[ 'backdrop-filter' ] )
50
+ );
51
+ stylesInheritanceTransformersRegistry.register(
52
+ 'transition',
53
+ createRepeaterToItemsTransformer( originalStyleTransformers.transition, ', ' )
54
+ );
55
+
56
+ [ 'background-overlay', 'box-shadow', 'transform-functions' ].forEach( ( propType ) =>
57
+ stylesInheritanceTransformersRegistry.register( propType, arrayTransformer )
58
+ );
38
59
  }
@@ -1,5 +1,14 @@
1
+ import { FIELD_TYPE, registerFieldIndicator } from '../field-indicators-registry';
2
+ import { StylesInheritanceIndicator } from './components/styles-inheritance-indicator';
1
3
  import { initStylesInheritanceTransformers } from './init-styles-inheritance-transformers';
2
4
 
3
5
  export const init = () => {
4
6
  initStylesInheritanceTransformers();
7
+
8
+ registerFieldIndicator( {
9
+ fieldType: FIELD_TYPE.STYLES,
10
+ id: 'styles-inheritance',
11
+ priority: 1,
12
+ indicator: StylesInheritanceIndicator,
13
+ } );
5
14
  };
@@ -3,9 +3,9 @@ import { type ReactNode } from 'react';
3
3
  import { createTransformer } from '@elementor/editor-canvas';
4
4
  import { Stack } from '@elementor/ui';
5
5
 
6
- type BackgroundOverlay = ReactNode[];
6
+ type ArrayValues = ReactNode[];
7
7
 
8
- export const backgroundOverlayTransformer = createTransformer( ( values: BackgroundOverlay[] ) => {
8
+ export const arrayTransformer = createTransformer( ( values: ArrayValues[] ) => {
9
9
  if ( ! values || values.length === 0 ) {
10
10
  return null;
11
11
  }
@@ -8,16 +8,10 @@ export type Color = {
8
8
 
9
9
  export const backgroundColorOverlayTransformer = createTransformer( ( value: Color ) => (
10
10
  <Stack direction="row" gap={ 1 } alignItems="center">
11
- <ItemIconColor value={ value } />
12
11
  <ItemLabelColor value={ value } />
13
12
  </Stack>
14
13
  ) );
15
14
 
16
- const ItemIconColor = ( { value }: { value: Color } ) => {
17
- const { color } = value;
18
- return <StyledUnstableColorIndicator size="inherit" component="span" value={ color } />;
19
- };
20
-
21
15
  const ItemLabelColor = ( { value: { color } }: { value: Color } ) => {
22
16
  return <span>{ color }</span>;
23
17
  };