@elementor/editor-editing-panel 1.27.0 → 1.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elementor/editor-editing-panel",
3
- "version": "1.27.0",
3
+ "version": "1.28.0",
4
4
  "private": false,
5
5
  "author": "Elementor Team",
6
6
  "homepage": "https://elementor.com/",
@@ -39,17 +39,17 @@
39
39
  "dev": "tsup --config=../../tsup.dev.ts"
40
40
  },
41
41
  "dependencies": {
42
- "@elementor/editor": "0.18.5",
43
- "@elementor/editor-canvas": "0.17.0",
44
- "@elementor/editor-controls": "0.24.0",
42
+ "@elementor/editor": "0.18.6",
43
+ "@elementor/editor-canvas": "0.18.0",
44
+ "@elementor/editor-controls": "0.25.0",
45
45
  "@elementor/editor-current-user": "0.3.0",
46
- "@elementor/editor-elements": "0.8.0",
47
- "@elementor/editor-panels": "0.14.0",
48
- "@elementor/editor-props": "0.11.1",
46
+ "@elementor/editor-elements": "0.8.1",
47
+ "@elementor/editor-panels": "0.14.1",
48
+ "@elementor/editor-props": "0.12.0",
49
49
  "@elementor/editor-responsive": "0.13.4",
50
- "@elementor/editor-styles": "0.6.5",
51
- "@elementor/editor-styles-repository": "0.8.3",
52
- "@elementor/editor-ui": "0.7.0",
50
+ "@elementor/editor-styles": "0.6.6",
51
+ "@elementor/editor-styles-repository": "0.8.4",
52
+ "@elementor/editor-ui": "0.7.1",
53
53
  "@elementor/editor-v1-adapters": "0.11.0",
54
54
  "@elementor/icons": "1.37.0",
55
55
  "@elementor/locations": "0.7.7",
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { type ReactElement, useState } from 'react';
3
- import { stylesRepository } from '@elementor/editor-styles-repository';
3
+ import { stylesRepository, validateStyleLabel } from '@elementor/editor-styles-repository';
4
4
  import { EditableField, EllipsisWithTooltip, useEditable } from '@elementor/editor-ui';
5
5
  import { DotsVerticalIcon } from '@elementor/icons';
6
6
  import {
@@ -21,8 +21,8 @@ import { CssClassMenu } from './css-class-menu';
21
21
 
22
22
  type CssClassItemProps = {
23
23
  id: string | null;
24
+ provider: string | null;
24
25
  label: string;
25
- provider: string;
26
26
  isActive: boolean;
27
27
  color: ChipOwnProps[ 'color' ];
28
28
  icon: ReactElement | null;
@@ -36,8 +36,8 @@ const CHIP_SIZE = 'tiny';
36
36
 
37
37
  export function CssClassItem( {
38
38
  id,
39
- label,
40
39
  provider,
40
+ label,
41
41
  isActive,
42
42
  color: colorProp,
43
43
  icon,
@@ -64,7 +64,7 @@ export function CssClassItem( {
64
64
 
65
65
  const color = error ? 'error' : colorProp;
66
66
 
67
- const providerActions = stylesRepository.getProviderByKey( provider )?.actions;
67
+ const providerActions = provider ? stylesRepository.getProviderByKey( provider )?.actions : null;
68
68
  const allowRename = Boolean( providerActions?.update );
69
69
 
70
70
  const isShowingState = isActive && meta.state;
@@ -153,13 +153,11 @@ export function CssClassItem( {
153
153
  }
154
154
 
155
155
  const validateLabel = ( newLabel: string ) => {
156
- if ( ! stylesRepository.isLabelValid( newLabel ) ) {
157
- return __( 'Invalid format', 'elementor' );
158
- }
156
+ const result = validateStyleLabel( newLabel );
159
157
 
160
- if ( stylesRepository.isLabelExist( newLabel ) ) {
161
- return __( 'Name exists', 'elementor' );
158
+ if ( result.isValid ) {
159
+ return null;
162
160
  }
163
161
 
164
- return null;
162
+ return result.error;
165
163
  };
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { type StyleDefinitionState } from '@elementor/editor-styles';
3
- import { ELEMENTS_STYLES_PROVIDER_KEY, stylesRepository } from '@elementor/editor-styles-repository';
3
+ import { isElementsStylesProvider, stylesRepository } from '@elementor/editor-styles-repository';
4
4
  import { MenuListItem } from '@elementor/editor-ui';
5
5
  import { bindMenu, Divider, Menu, MenuSubheader, type PopupState, Stack } from '@elementor/ui';
6
6
  import { __ } from '@wordpress/i18n';
@@ -14,7 +14,7 @@ const STATES: NonNullable< StyleDefinitionState >[] = [ 'hover', 'focus', 'activ
14
14
 
15
15
  type CssClassMenuProps = {
16
16
  styleId: string | null;
17
- provider: string;
17
+ provider: string | null;
18
18
  popupState: PopupState;
19
19
  handleRename: () => void;
20
20
  anchorEl: HTMLElement | null;
@@ -23,7 +23,7 @@ type CssClassMenuProps = {
23
23
  export function CssClassMenu( { styleId, provider, popupState, handleRename, anchorEl }: CssClassMenuProps ) {
24
24
  const styledStates = useStyledStates( styleId );
25
25
 
26
- const indicatorVariant = provider === ELEMENTS_STYLES_PROVIDER_KEY ? 'local' : 'global';
26
+ const indicatorVariant = ! provider || isElementsStylesProvider( provider ) ? 'local' : 'global';
27
27
 
28
28
  const handleKeyDown = ( e: React.KeyboardEvent< HTMLElement > ) => {
29
29
  e.stopPropagation();
@@ -43,6 +43,8 @@ export function CssClassMenu( { styleId, provider, popupState, handleRename, anc
43
43
  vertical: -4,
44
44
  } }
45
45
  onKeyDown={ handleKeyDown }
46
+ // Workaround for focus-visible issue.
47
+ disableAutoFocusItem
46
48
  >
47
49
  { /* It has to be an array since MUI menu doesn't accept a Fragment as a child, and wrapping the items with an HTML element disrupts keyboard navigation */ }
48
50
  { getMenuItemsByProvider( { provider, styleId, handleRename, closeMenu: popupState.close } ) }
@@ -91,12 +93,12 @@ function getMenuItemsByProvider( {
91
93
  handleRename,
92
94
  closeMenu,
93
95
  }: {
94
- provider: string;
96
+ provider: string | null;
95
97
  styleId: string | null;
96
98
  handleRename: () => void;
97
99
  closeMenu: () => void;
98
100
  } ) {
99
- if ( ! styleId ) {
101
+ if ( ! styleId || ! provider ) {
100
102
  return [];
101
103
  }
102
104
 
@@ -4,16 +4,17 @@ import { getElementSetting, updateElementSettings, useElementSetting } from '@el
4
4
  import { classesPropTypeUtil, type ClassesPropValue } from '@elementor/editor-props';
5
5
  import { type StyleDefinitionID } from '@elementor/editor-styles';
6
6
  import {
7
- ELEMENTS_STYLES_PROVIDER_KEY,
7
+ isElementsStylesProvider,
8
8
  type StylesProvider,
9
9
  stylesRepository,
10
10
  type UpdateActionPayload,
11
11
  useCreateActionsByProvider,
12
12
  useProviders,
13
+ validateStyleLabel,
13
14
  } from '@elementor/editor-styles-repository';
14
15
  import { MapPinIcon } from '@elementor/icons';
15
16
  import { createLocation } from '@elementor/locations';
16
- import { Chip, Stack, Typography } from '@elementor/ui';
17
+ import { Chip, FormLabel, Stack } from '@elementor/ui';
17
18
  import { __ } from '@wordpress/i18n';
18
19
 
19
20
  import { useClassesProp } from '../../contexts/classes-prop-context';
@@ -28,7 +29,7 @@ const TAGS_LIMIT = 50;
28
29
  type StyleDefOption = Option & {
29
30
  color: 'accent' | 'global';
30
31
  icon: ReactElement | null;
31
- provider: string;
32
+ provider: string | null;
32
33
  };
33
34
 
34
35
  const EMPTY_OPTION = {
@@ -37,7 +38,7 @@ const EMPTY_OPTION = {
37
38
  fixed: true,
38
39
  color: 'accent',
39
40
  icon: <MapPinIcon />,
40
- provider: ELEMENTS_STYLES_PROVIDER_KEY,
41
+ provider: null,
41
42
  } satisfies StyleDefOption;
42
43
 
43
44
  export const { Slot: ClassSelectorActionsSlot, inject: injectIntoClassSelectorActions } = createLocation();
@@ -60,12 +61,14 @@ export function CssClassSelector() {
60
61
  const applied = useAppliedOptions( options, appliedIds );
61
62
  const active = applied.find( ( option ) => option.value === activeId ) ?? EMPTY_OPTION;
62
63
 
64
+ const showPlaceholder = applied.every( ( { fixed } ) => fixed );
65
+
63
66
  return (
64
- <Stack gap={ 1 } p={ 2 }>
67
+ <Stack p={ 2 }>
65
68
  <Stack direction="row" gap={ 1 } alignItems="center" justifyContent="space-between">
66
- <Typography component="label" variant="caption" htmlFor={ ID }>
69
+ <FormLabel htmlFor={ ID } size="small">
67
70
  { __( 'Classes', 'elementor' ) }
68
- </Typography>
71
+ </FormLabel>
69
72
  <Stack direction="row" gap={ 1 }>
70
73
  <ClassSelectorActionsSlot />
71
74
  </Stack>
@@ -73,6 +76,7 @@ export function CssClassSelector() {
73
76
  <MultiCombobox
74
77
  id={ ID }
75
78
  size="tiny"
79
+ placeholder={ showPlaceholder ? __( 'Type to search/add global classes', 'elementor' ) : undefined }
76
80
  options={ options }
77
81
  selected={ applied }
78
82
  onSelect={ handleApply }
@@ -114,7 +118,11 @@ export function CssClassSelector() {
114
118
  );
115
119
  }
116
120
 
117
- const updateClassByProvider = ( provider: string, data: UpdateActionPayload ) => {
121
+ const updateClassByProvider = ( provider: string | null, data: UpdateActionPayload ) => {
122
+ if ( ! provider ) {
123
+ return;
124
+ }
125
+
118
126
  const providerInstance = stylesRepository.getProviderByKey( provider );
119
127
 
120
128
  if ( ! providerInstance ) {
@@ -132,8 +140,8 @@ function useOptions() {
132
140
  return useProviders()
133
141
  .filter( isProviderEditable )
134
142
  .flatMap< StyleDefOption >( ( provider ) => {
135
- const isElements = provider.key === ELEMENTS_STYLES_PROVIDER_KEY;
136
- const styleDefs = provider.actions.get( { elementId: element.id } );
143
+ const isElements = isElementsStylesProvider( provider.getKey() );
144
+ const styleDefs = provider.actions.all( { elementId: element.id } );
137
145
 
138
146
  // Add empty local option for elements, as fallback.
139
147
  if ( isElements && styleDefs.length === 0 ) {
@@ -147,7 +155,7 @@ function useOptions() {
147
155
  fixed: isElements,
148
156
  color: isElements ? 'accent' : 'global',
149
157
  icon: isElements ? <MapPinIcon /> : null,
150
- provider: provider.key,
158
+ provider: provider.getKey(),
151
159
  // translators: %s is the plural label of the provider (e.g "Existing classes").
152
160
  group: __( 'Existing %s', 'elementor' ).replace( '%s', provider.labels?.plural ?? '' ),
153
161
  };
@@ -168,7 +176,7 @@ function useCreateActions( {
168
176
  label: ( value ) => __( 'Create "%s"', 'elementor' ).replace( '%s', value ),
169
177
  // translators: %s is the singular label of css class provider (e.g "CSS Class").
170
178
  group: __( 'Create a new %s', 'elementor' ).replace( '%s', provider.labels?.singular ?? '' ),
171
- condition: ( _, inputValue ) => isLabelValid( inputValue ) && ! hasReachedLimit( provider ),
179
+ condition: ( _, inputValue ) => validateStyleLabel( inputValue ).isValid && ! hasReachedLimit( provider ),
172
180
  apply: ( label ) => {
173
181
  const createdId = create( label );
174
182
 
@@ -184,22 +192,14 @@ function useCreateActions( {
184
192
  }
185
193
 
186
194
  function hasReachedLimit( provider: StylesProvider ) {
187
- if ( provider.limit === undefined ) {
188
- return false;
189
- }
190
-
191
- return provider.actions.get().length >= provider.limit;
192
- }
193
-
194
- function isLabelValid( newLabel: string ) {
195
- return stylesRepository.isLabelValid( newLabel ) && ! stylesRepository.isLabelExist( newLabel );
195
+ return provider.actions.all().length >= provider.limit;
196
196
  }
197
197
 
198
198
  function useAppliedOptions( options: StyleDefOption[], appliedIds: StyleDefinitionID[] ) {
199
199
  const applied = options.filter( ( option ) => option.value && appliedIds.includes( option.value ) );
200
200
 
201
201
  const hasElementsProviderStyleApplied = applied.some(
202
- ( option ) => option.provider === ELEMENTS_STYLES_PROVIDER_KEY
202
+ ( option ) => option.provider && isElementsStylesProvider( option.provider )
203
203
  );
204
204
 
205
205
  if ( ! hasElementsProviderStyleApplied ) {
@@ -39,6 +39,7 @@ type Props< TOption extends Option > = Omit<
39
39
  selected: TOption[];
40
40
  options: TOption[];
41
41
  onSelect?: ( value: TOption[] ) => void;
42
+ placeholder?: string;
42
43
  };
43
44
 
44
45
  export function MultiCombobox< TOption extends Option >( {
@@ -46,6 +47,7 @@ export function MultiCombobox< TOption extends Option >( {
46
47
  selected,
47
48
  options,
48
49
  onSelect,
50
+ placeholder,
49
51
  ...props
50
52
  }: Props< TOption > ) {
51
53
  const filter = useFilterOptions< TOption >();
@@ -67,6 +69,7 @@ export function MultiCombobox< TOption extends Option >( {
67
69
  renderInput={ ( params ) => (
68
70
  <TextField
69
71
  { ...params }
72
+ placeholder={ placeholder }
70
73
  sx={ ( theme: Theme ) => ( {
71
74
  '.MuiAutocomplete-inputRoot.MuiInputBase-adornedStart': {
72
75
  paddingLeft: theme.spacing( 0.25 ),
@@ -3,45 +3,51 @@ import { type ToggleButtonGroupItem, ToggleControl } from '@elementor/editor-con
3
3
  import { Stack } from '@elementor/ui';
4
4
  import { __ } from '@wordpress/i18n';
5
5
 
6
+ import { useStylesInheritanceField } from '../../../contexts/styles-inheritance-context';
6
7
  import { StylesField } from '../../../controls-registry/styles-field';
7
8
  import { ControlLabel } from '../../control-label';
8
9
 
9
10
  type Displays = 'block' | 'flex' | 'inline-block' | 'inline-flex';
10
11
 
12
+ const displayFieldOptions: ToggleButtonGroupItem< Displays >[] = [
13
+ {
14
+ value: 'block',
15
+ renderContent: () => __( 'Block', 'elementor' ),
16
+ label: __( 'Block', 'elementor' ),
17
+ showTooltip: true,
18
+ },
19
+ {
20
+ value: 'flex',
21
+ renderContent: () => __( 'Flex', 'elementor' ),
22
+ label: __( 'Flex', 'elementor' ),
23
+ showTooltip: true,
24
+ },
25
+ {
26
+ value: 'inline-block',
27
+ renderContent: () => __( 'In-blk', 'elementor' ),
28
+ label: __( 'Inline-block', 'elementor' ),
29
+ showTooltip: true,
30
+ },
31
+ {
32
+ value: 'inline-flex',
33
+ renderContent: () => __( 'In-flx', 'elementor' ),
34
+ label: __( 'Inline-flex', 'elementor' ),
35
+ showTooltip: true,
36
+ },
37
+ ];
38
+
11
39
  export const DisplayField = () => {
12
- const options: ToggleButtonGroupItem< Displays >[] = [
13
- {
14
- value: 'block',
15
- renderContent: () => __( 'Block', 'elementor' ),
16
- label: __( 'Block', 'elementor' ),
17
- showTooltip: true,
18
- },
19
- {
20
- value: 'flex',
21
- renderContent: () => __( 'Flex', 'elementor' ),
22
- label: __( 'Flex', 'elementor' ),
23
- showTooltip: true,
24
- },
25
- {
26
- value: 'inline-block',
27
- renderContent: () => __( 'In-blk', 'elementor' ),
28
- label: __( 'Inline-block', 'elementor' ),
29
- showTooltip: true,
30
- },
31
- {
32
- value: 'inline-flex',
33
- renderContent: () => __( 'In-flx', 'elementor' ),
34
- label: __( 'Inline-flex', 'elementor' ),
35
- showTooltip: true,
36
- },
37
- ];
40
+ const placeholder = useDisplayPlaceholderValue();
38
41
 
39
42
  return (
40
- <StylesField bind="display">
43
+ <StylesField bind="display" placeholder={ placeholder }>
41
44
  <Stack gap={ 0.75 }>
42
45
  <ControlLabel>{ __( 'Display', 'elementor' ) }</ControlLabel>
43
- <ToggleControl options={ options } fullWidth={ true } />
46
+ <ToggleControl options={ displayFieldOptions } fullWidth={ true } />
44
47
  </Stack>
45
48
  </StylesField>
46
49
  );
47
50
  };
51
+
52
+ // TODO - placing this logic deliberately here, and will be removed once applied automatically to all style fields as part of ED-18491
53
+ export const useDisplayPlaceholderValue = () => useStylesInheritanceField( 'display' )[ 0 ]?.value ?? undefined;
@@ -12,7 +12,7 @@ import { SectionContent } from '../../section-content';
12
12
  import { AlignContentField } from './align-content-field';
13
13
  import { AlignItemsField } from './align-items-field';
14
14
  import { AlignSelfChild } from './align-self-child-field';
15
- import { DisplayField } from './display-field';
15
+ import { DisplayField, useDisplayPlaceholderValue } from './display-field';
16
16
  import { FlexDirectionField } from './flex-direction-field';
17
17
  import { FlexOrderField } from './flex-order-field';
18
18
  import { FlexSizeField } from './flex-size-field';
@@ -22,6 +22,8 @@ import { WrapField } from './wrap-field';
22
22
 
23
23
  export const LayoutSection = () => {
24
24
  const [ display ] = useStylesField< StringPropValue >( 'display' );
25
+ const displayPlaceholder = useDisplayPlaceholderValue();
26
+ const isDisplayFlex = shouldDisplayFlexFields( display, displayPlaceholder as StringPropValue );
25
27
  const { element } = useElement();
26
28
  const parent = useParentElement( element.id );
27
29
  const parentStyle = useComputedStyle( parent?.id || null );
@@ -29,7 +31,7 @@ export const LayoutSection = () => {
29
31
  return (
30
32
  <SectionContent>
31
33
  <DisplayField />
32
- { ( 'flex' === display?.value || 'inline-flex' === display?.value ) && <FlexFields /> }
34
+ { isDisplayFlex && <FlexFields /> }
33
35
  { 'flex' === parentStyle?.display && <FlexChildFields /> }
34
36
  </SectionContent>
35
37
  );
@@ -60,3 +62,13 @@ const FlexChildFields = () => (
60
62
  <FlexSizeField />
61
63
  </>
62
64
  );
65
+
66
+ const shouldDisplayFlexFields = ( display: StringPropValue | null, local: StringPropValue ) => {
67
+ const value = display?.value ?? local?.value;
68
+
69
+ if ( ! value ) {
70
+ return false;
71
+ }
72
+
73
+ return 'flex' === value || 'inline-flex' === value;
74
+ };
@@ -1,7 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { useState } from 'react';
3
- import { getElementStyles, useElementSetting } from '@elementor/editor-elements';
4
- import { CLASSES_PROP_KEY, type ClassesPropValue, type PropKey } from '@elementor/editor-props';
3
+ import { CLASSES_PROP_KEY } from '@elementor/editor-props';
5
4
  import { useActiveBreakpoint } from '@elementor/editor-responsive';
6
5
  import { type StyleDefinitionID, type StyleDefinitionState } from '@elementor/editor-styles';
7
6
  import { SessionStorageProvider } from '@elementor/session';
@@ -12,6 +11,7 @@ import { ClassesPropProvider } from '../contexts/classes-prop-context';
12
11
  import { useElement } from '../contexts/element-context';
13
12
  import { StyleProvider } from '../contexts/style-context';
14
13
  import { StyleInheritanceProvider } from '../contexts/styles-inheritance-context';
14
+ import { useActiveStyleDefId } from '../hooks/use-active-style-def-id';
15
15
  import { CssClassSelector } from './css-classes/css-class-selector';
16
16
  import { Section } from './section';
17
17
  import { SectionsList } from './sections-list';
@@ -78,23 +78,6 @@ export const StyleTab = () => {
78
78
  );
79
79
  };
80
80
 
81
- function useActiveStyleDefId( currentClassesProp: PropKey ) {
82
- const [ activeStyledDefId, setActiveStyledDefId ] = useState< StyleDefinitionID | null >( null );
83
-
84
- const fallback = useFirstElementStyleDef( currentClassesProp );
85
-
86
- return [ activeStyledDefId || fallback?.id || null, setActiveStyledDefId ] as const;
87
- }
88
-
89
- function useFirstElementStyleDef( currentClassesProp: PropKey ) {
90
- const { element } = useElement();
91
-
92
- const classesIds = useElementSetting< ClassesPropValue >( element.id, currentClassesProp )?.value || [];
93
- const stylesDefs = getElementStyles( element.id ) ?? {};
94
-
95
- return Object.values( stylesDefs ).find( ( styleDef ) => classesIds.includes( styleDef.id ) );
96
- }
97
-
98
81
  function useCurrentClassesProp(): string {
99
82
  const { elementType } = useElement();
100
83
 
@@ -52,7 +52,7 @@ export function useStyle() {
52
52
 
53
53
  export function getProviderByStyleId( styleId: StyleDefinitionID ) {
54
54
  const styleProvider = stylesRepository.getProviders().find( ( provider ) => {
55
- return provider.actions.get().find( ( style ) => style.id === styleId );
55
+ return provider.actions.all().find( ( style ) => style.id === styleId );
56
56
  } );
57
57
 
58
58
  return styleProvider ?? null;
@@ -9,10 +9,11 @@ import { createTopLevelOjectType } from './create-top-level-object-type';
9
9
 
10
10
  export type StylesFieldProps = {
11
11
  bind: PropKey;
12
+ placeholder?: PropValue;
12
13
  children: React.ReactNode;
13
14
  };
14
15
 
15
- export const StylesField = ( { bind, children }: StylesFieldProps ) => {
16
+ export const StylesField = ( { bind, placeholder, children }: StylesFieldProps ) => {
16
17
  const [ value, setValue ] = useStylesField( bind );
17
18
 
18
19
  const stylesSchema = getStylesSchema();
@@ -20,6 +21,7 @@ export const StylesField = ( { bind, children }: StylesFieldProps ) => {
20
21
  const propType = createTopLevelOjectType( { schema: stylesSchema } );
21
22
 
22
23
  const values = { [ bind ]: value };
24
+ const placeholderValues = { [ bind ]: placeholder };
23
25
 
24
26
  const setValues = ( newValue: Record< string, PropValue > ) => {
25
27
  setValue( newValue[ bind ] );
@@ -34,7 +36,12 @@ export const StylesField = ( { bind, children }: StylesFieldProps ) => {
34
36
  },
35
37
  ] }
36
38
  >
37
- <PropProvider propType={ propType } value={ values } setValue={ setValues }>
39
+ <PropProvider
40
+ propType={ propType }
41
+ value={ values }
42
+ setValue={ setValues }
43
+ placeholder={ placeholderValues }
44
+ >
38
45
  <PropKeyProvider bind={ bind }>{ children }</PropKeyProvider>
39
46
  </PropProvider>
40
47
  </ControlAdornmentsProvider>
@@ -0,0 +1,36 @@
1
+ import { useState } from 'react';
2
+ import { getElementStyles, useElementSetting } from '@elementor/editor-elements';
3
+ import { type ClassesPropValue, type PropKey } from '@elementor/editor-props';
4
+ import { type StyleDefinitionID } from '@elementor/editor-styles';
5
+
6
+ import { useElement } from '../contexts/element-context';
7
+
8
+ export function useActiveStyleDefId( classProp: PropKey ) {
9
+ const [ activeStyledDefId, setActiveStyledDefId ] = useState< StyleDefinitionID | null >( null );
10
+
11
+ const appliedClassesIds = useAppliedClassesIds( classProp )?.value || [];
12
+
13
+ const fallback = useFirstAppliedClass( appliedClassesIds );
14
+
15
+ const activeAndAppliedClassId = useActiveAndAppliedClassId( activeStyledDefId, appliedClassesIds );
16
+ return [ activeAndAppliedClassId || fallback?.id || null, setActiveStyledDefId ] as const;
17
+ }
18
+
19
+ function useFirstAppliedClass( appliedClassesIds: string[] ) {
20
+ const { element } = useElement();
21
+ const stylesDefs = getElementStyles( element.id ) ?? {};
22
+
23
+ return Object.values( stylesDefs ).find( ( styleDef ) => appliedClassesIds.includes( styleDef.id ) );
24
+ }
25
+
26
+ function useAppliedClassesIds( classProp: PropKey ) {
27
+ const { element } = useElement();
28
+
29
+ return useElementSetting< ClassesPropValue >( element.id, classProp );
30
+ }
31
+
32
+ function useActiveAndAppliedClassId( id: StyleDefinitionID | null, appliedClassesIds: string[] ) {
33
+ const isClassApplied = !! id && appliedClassesIds.includes( id );
34
+
35
+ return isClassApplied ? id : null;
36
+ }
@@ -9,7 +9,7 @@ import {
9
9
  import type { Props } from '@elementor/editor-props';
10
10
  import { getVariantByMeta, type StyleDefinition, type StyleDefinitionVariant } from '@elementor/editor-styles';
11
11
  import { type StylesProvider } from '@elementor/editor-styles-repository';
12
- import { LOCAL_STYLES_RESERVED_LABEL } from '@elementor/editor-styles-repository';
12
+ import { ELEMENTS_STYLES_RESERVED_LABEL } from '@elementor/editor-styles-repository';
13
13
  import { undoable } from '@elementor/editor-v1-adapters';
14
14
  import { __ } from '@wordpress/i18n';
15
15
 
@@ -78,10 +78,10 @@ function getProps< T extends Props >( { styleId, elementId, provider, meta, prop
78
78
  return null;
79
79
  }
80
80
 
81
- const style = provider.actions.getById?.( styleId, { elementId } );
81
+ const style = provider.actions.get( styleId, { elementId } );
82
82
 
83
83
  if ( ! style ) {
84
- throw new StyleNotFoundUnderProviderError( { context: { styleId, providerKey: provider.key } } );
84
+ throw new StyleNotFoundUnderProviderError( { context: { styleId, providerKey: provider.getKey() } } );
85
85
  }
86
86
 
87
87
  const variant = getVariantByMeta( style, meta );
@@ -100,7 +100,7 @@ function useUndoableCreateElementStyle() {
100
100
  do: ( payload: UndoableCreateElementStyleArgs ) => {
101
101
  return createElementStyle( {
102
102
  ...payload,
103
- label: LOCAL_STYLES_RESERVED_LABEL,
103
+ label: ELEMENTS_STYLES_RESERVED_LABEL,
104
104
  } );
105
105
  },
106
106
 
@@ -112,7 +112,7 @@ function useUndoableCreateElementStyle() {
112
112
  return createElementStyle( {
113
113
  ...payload,
114
114
  styleId,
115
- label: LOCAL_STYLES_RESERVED_LABEL,
115
+ label: ELEMENTS_STYLES_RESERVED_LABEL,
116
116
  } );
117
117
  },
118
118
  },
@@ -139,11 +139,11 @@ function useUndoableUpdateStyle() {
139
139
  do: ( { elementId, styleId, provider, meta, props }: UndoableUpdateStyleArgs ) => {
140
140
  if ( ! provider.actions.updateProps ) {
141
141
  throw new StylesProviderCannotUpdatePropsError( {
142
- context: { providerKey: provider.key },
142
+ context: { providerKey: provider.getKey() },
143
143
  } );
144
144
  }
145
145
 
146
- const style = provider.actions.getById( styleId, { elementId } );
146
+ const style = provider.actions.get( styleId, { elementId } );
147
147
 
148
148
  const prevProps = getCurrentProps( style, meta );
149
149
 
package/src/index.ts CHANGED
@@ -4,6 +4,4 @@ export { replaceControl } from './control-replacement';
4
4
  export { injectIntoClassSelectorActions } from './components/css-classes/css-class-selector';
5
5
  export { usePanelActions, usePanelStatus } from './panel';
6
6
 
7
- import init from './init';
8
-
9
- init();
7
+ export { init } from './init';
package/src/init.ts CHANGED
@@ -8,7 +8,7 @@ import { init as initDynamics } from './dynamics/init';
8
8
  import { panel } from './panel';
9
9
  import { isAtomicWidgetSelected } from './sync/is-atomic-widget-selected';
10
10
 
11
- export default function init() {
11
+ export function init() {
12
12
  registerPanel( panel );
13
13
  blockV1Panel();
14
14
 
@@ -1,3 +1,4 @@
1
+ import { filterEmptyValues } from '@elementor/editor-props';
1
2
  import { type BreakpointId, type BreakpointNode } from '@elementor/editor-responsive';
2
3
  import { type StyleDefinitionState } from '@elementor/editor-styles';
3
4
 
@@ -141,13 +142,19 @@ function buildInitialSnapshotFromStyles( styles: StyleVariantDetails[] ): Styles
141
142
  } = styleData;
142
143
 
143
144
  Object.entries( props ).forEach( ( [ key, value ] ) => {
145
+ const filteredValue = filterEmptyValues( value );
146
+
147
+ if ( filteredValue === null ) {
148
+ return;
149
+ }
150
+
144
151
  if ( ! snapshot[ key ] ) {
145
152
  snapshot[ key ] = [];
146
153
  }
147
154
 
148
155
  const snapshotPropValue: SnapshotPropValue = {
149
156
  ...styleData,
150
- value,
157
+ value: filteredValue,
151
158
  };
152
159
 
153
160
  snapshot[ key ].push( snapshotPropValue );
@@ -22,7 +22,7 @@ function buildStyleVariantsByMetaMapping( styleDefs: StyleDefinition[] ): Breakp
22
22
  const breakpointStateSlots: BreakpointsStatesStyles = {};
23
23
 
24
24
  styleDefs.forEach( ( styleDef ) => {
25
- const provider = getProviderByStyleId( styleDef.id )?.key ?? null;
25
+ const provider = getProviderByStyleId( styleDef.id )?.getKey() ?? null;
26
26
 
27
27
  // iterate over each style definition's variants and place them in the corresponding breakpoint's base or state styles
28
28
  styleDef.variants.forEach( ( variant ) => {
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { useBoundProp } from '@elementor/editor-controls';
3
- import { ELEMENTS_BASE_STYLES_PROVIDER_KEY, ELEMENTS_STYLES_PROVIDER_KEY } from '@elementor/editor-styles-repository';
3
+ import { ELEMENTS_BASE_STYLES_PROVIDER_KEY, isElementsStylesProvider } from '@elementor/editor-styles-repository';
4
4
  import { __ } from '@wordpress/i18n';
5
5
 
6
6
  import { StyleIndicator } from '../components/style-indicator';
@@ -35,7 +35,7 @@ export const StylesInheritanceIndicator = () => {
35
35
  return (
36
36
  <StyleIndicator
37
37
  aria-label={ __( 'This is the final value', 'elementor' ) }
38
- variant={ currentStyleProvider?.key === ELEMENTS_STYLES_PROVIDER_KEY ? 'local' : 'global' }
38
+ variant={ isElementsStylesProvider( currentStyleProvider?.getKey() ) ? 'local' : 'global' }
39
39
  />
40
40
  );
41
41
  }