@elementor/editor-editing-panel 1.48.0 → 3.32.0-20

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 (61) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/index.d.mts +78 -47
  3. package/dist/index.d.ts +78 -47
  4. package/dist/index.js +1770 -1406
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +1550 -1157
  7. package/dist/index.mjs.map +1 -1
  8. package/package.json +22 -22
  9. package/src/components/css-classes/css-class-convert-local.tsx +77 -0
  10. package/src/components/css-classes/css-class-item.tsx +18 -3
  11. package/src/components/css-classes/css-class-menu.tsx +10 -3
  12. package/src/components/css-classes/css-class-selector.tsx +10 -2
  13. package/src/components/css-classes/local-class-sub-menu.tsx +23 -0
  14. package/src/components/css-classes/use-apply-and-unapply-class.ts +7 -50
  15. package/src/components/css-classes/use-can-convert-local-class-to-global.ts +22 -0
  16. package/src/components/custom-css.tsx +21 -0
  17. package/src/components/editing-panel-tabs.tsx +1 -5
  18. package/src/components/popover-body.tsx +12 -0
  19. package/src/components/section.tsx +1 -5
  20. package/src/components/settings-tab.tsx +6 -15
  21. package/src/components/style-sections/effects-section/effects-section.tsx +32 -19
  22. package/src/components/style-sections/layout-section/display-field.tsx +11 -20
  23. package/src/components/style-sections/layout-section/flex-order-field.tsx +6 -1
  24. package/src/components/style-sections/layout-section/flex-size-field.tsx +86 -52
  25. package/src/components/style-sections/position-section/offset-field.tsx +2 -2
  26. package/src/components/style-sections/position-section/position-section.tsx +2 -8
  27. package/src/components/style-sections/size-section/size-section.tsx +16 -31
  28. package/src/components/style-sections/typography-section/typography-section.tsx +2 -19
  29. package/src/components/style-tab-collapsible-content.tsx +1 -5
  30. package/src/components/style-tab-section.tsx +1 -5
  31. package/src/components/style-tab.tsx +15 -2
  32. package/src/controls-actions.ts +1 -1
  33. package/src/controls-registry/conditional-field.tsx +26 -0
  34. package/src/controls-registry/control.tsx +2 -2
  35. package/src/controls-registry/controls-registry.tsx +44 -3
  36. package/src/controls-registry/settings-field.tsx +33 -45
  37. package/src/controls-registry/styles-field.tsx +14 -14
  38. package/src/dynamics/components/dynamic-selection-control.tsx +24 -16
  39. package/src/dynamics/components/dynamic-selection.tsx +32 -36
  40. package/src/errors.ts +10 -0
  41. package/src/hooks/use-custom-css.ts +184 -0
  42. package/src/hooks/use-state-by-element.ts +1 -4
  43. package/src/hooks/use-styles-fields.ts +129 -106
  44. package/src/index.ts +9 -10
  45. package/src/init.ts +2 -5
  46. package/src/popover-action.tsx +36 -15
  47. package/src/reset-style-props.tsx +2 -6
  48. package/src/styles-inheritance/components/infotip/value-component.tsx +1 -0
  49. package/src/styles-inheritance/components/styles-inheritance-indicator.tsx +6 -23
  50. package/src/styles-inheritance/components/styles-inheritance-infotip.tsx +18 -9
  51. package/src/styles-inheritance/consts.ts +0 -4
  52. package/src/styles-inheritance/init.ts +1 -4
  53. package/src/styles-inheritance/transformers/background-color-overlay-transformer.tsx +5 -1
  54. package/src/styles-inheritance/transformers/background-gradient-overlay-transformer.tsx +3 -3
  55. package/src/styles-inheritance/transformers/background-image-overlay-transformer.tsx +2 -1
  56. package/src/utils/get-styles-provider-color.ts +8 -0
  57. package/src/utils/prop-dependency-utils.ts +156 -0
  58. package/src/components/popover-scrollable-content.tsx +0 -12
  59. package/src/components/style-sections/size-section/object-position-field.tsx +0 -15
  60. package/src/sync/experiments-flags.ts +0 -5
  61. /package/src/components/style-sections/{layout-section → effects-section}/opacity-control-field.tsx +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elementor/editor-editing-panel",
3
- "version": "1.48.0",
3
+ "version": "3.32.0-20",
4
4
  "private": false,
5
5
  "author": "Elementor Team",
6
6
  "homepage": "https://elementor.com/",
@@ -18,11 +18,11 @@
18
18
  },
19
19
  "repository": {
20
20
  "type": "git",
21
- "url": "git+https://github.com/elementor/elementor-packages.git",
21
+ "url": "git+https://github.com/elementor/elementor.git",
22
22
  "directory": "packages/core/editor-editing-panel"
23
23
  },
24
24
  "bugs": {
25
- "url": "https://github.com/elementor/elementor-packages/issues"
25
+ "url": "https://github.com/elementor/elementor/issues"
26
26
  },
27
27
  "publishConfig": {
28
28
  "access": "public"
@@ -39,26 +39,26 @@
39
39
  "dev": "tsup --config=../../tsup.dev.ts"
40
40
  },
41
41
  "dependencies": {
42
- "@elementor/editor": "0.21.0",
43
- "@elementor/editor-canvas": "0.26.0",
44
- "@elementor/editor-controls": "1.3.0",
45
- "@elementor/editor-documents": "0.13.9",
46
- "@elementor/editor-elements": "0.9.0",
47
- "@elementor/editor-panels": "0.17.0",
48
- "@elementor/editor-props": "0.16.0",
49
- "@elementor/editor-responsive": "0.13.6",
50
- "@elementor/editor-styles": "0.6.12",
51
- "@elementor/editor-styles-repository": "0.10.5",
52
- "@elementor/editor-ui": "0.14.0",
53
- "@elementor/editor-v1-adapters": "0.12.1",
42
+ "@elementor/editor": "3.32.0-20",
43
+ "@elementor/editor-canvas": "3.32.0-20",
44
+ "@elementor/editor-controls": "3.32.0-20",
45
+ "@elementor/editor-documents": "3.32.0-20",
46
+ "@elementor/editor-elements": "3.32.0-20",
47
+ "@elementor/editor-panels": "3.32.0-20",
48
+ "@elementor/editor-props": "3.32.0-20",
49
+ "@elementor/editor-responsive": "3.32.0-20",
50
+ "@elementor/editor-styles": "3.32.0-20",
51
+ "@elementor/editor-styles-repository": "3.32.0-20",
52
+ "@elementor/editor-ui": "3.32.0-20",
53
+ "@elementor/editor-v1-adapters": "3.32.0-20",
54
54
  "@elementor/icons": "1.46.0",
55
- "@elementor/locations": "0.8.0",
56
- "@elementor/menus": "0.1.5",
57
- "@elementor/schema": "0.1.2",
58
- "@elementor/session": "0.1.0",
59
- "@elementor/ui": "1.36.0",
60
- "@elementor/utils": "0.5.0",
61
- "@elementor/wp-media": "0.6.1",
55
+ "@elementor/locations": "3.32.0-20",
56
+ "@elementor/menus": "3.32.0-20",
57
+ "@elementor/schema": "3.32.0-20",
58
+ "@elementor/session": "3.32.0-20",
59
+ "@elementor/ui": "1.36.2",
60
+ "@elementor/utils": "3.32.0-20",
61
+ "@elementor/wp-media": "3.32.0-20",
62
62
  "@wordpress/i18n": "^5.13.0"
63
63
  },
64
64
  "peerDependencies": {
@@ -0,0 +1,77 @@
1
+ import * as React from 'react';
2
+ import { deleteElementStyle, getElementSetting, updateElementSettings } from '@elementor/editor-elements';
3
+ import { classesPropTypeUtil, type ClassesPropValue } from '@elementor/editor-props';
4
+ import { type StyleDefinition } from '@elementor/editor-styles';
5
+ import { createLocation } from '@elementor/locations';
6
+ import { useSessionStorage } from '@elementor/session';
7
+
8
+ import { useClassesProp } from '../../contexts/classes-prop-context';
9
+ import { useElement } from '../../contexts/element-context';
10
+ import { useStyle } from '../../contexts/style-context';
11
+
12
+ export const { Slot: CssClassConvertSlot, inject: injectIntoCssClassConvert } = createLocation< {
13
+ styleDef: StyleDefinition | null;
14
+ successCallback: ( newId: string ) => void;
15
+ canConvert: boolean;
16
+ } >();
17
+
18
+ type OwnProps = {
19
+ styleDef: StyleDefinition | null;
20
+ closeMenu: () => void;
21
+ canConvert: boolean;
22
+ };
23
+
24
+ /**
25
+ * Convert a local class to a global class injection point
26
+ * @param props
27
+ */
28
+ export const CssClassConvert = ( props: OwnProps ) => {
29
+ const { element } = useElement();
30
+ const elementId = element.id;
31
+ const currentClassesProp = useClassesProp();
32
+ const { setId: setActiveId } = useStyle();
33
+ const [ , saveValue ] = useSessionStorage( `last-converted-class-generated-name` );
34
+
35
+ const successCallback = ( newId: string ) => {
36
+ if ( ! props.styleDef ) {
37
+ throw new Error( 'Style definition is required for converting local class to global class.' );
38
+ }
39
+
40
+ onConvert( {
41
+ newId,
42
+ elementId,
43
+ classesProp: currentClassesProp,
44
+ styleDef: props.styleDef,
45
+ } );
46
+
47
+ saveValue( newId );
48
+ setActiveId( newId );
49
+ props.closeMenu();
50
+ };
51
+
52
+ return (
53
+ <CssClassConvertSlot
54
+ canConvert={ !! props.canConvert }
55
+ styleDef={ props.styleDef }
56
+ successCallback={ successCallback }
57
+ />
58
+ );
59
+ };
60
+
61
+ type OnConvertOptions = {
62
+ newId: string;
63
+ elementId: string;
64
+ classesProp: string;
65
+ styleDef: StyleDefinition;
66
+ };
67
+
68
+ const onConvert = ( opts: OnConvertOptions ) => {
69
+ const { newId, elementId, classesProp } = opts;
70
+ deleteElementStyle( elementId, opts.styleDef.id );
71
+ const currentUsedClasses = getElementSetting< ClassesPropValue >( elementId, classesProp ) || { value: [] };
72
+ updateElementSettings( {
73
+ id: elementId,
74
+ props: { [ classesProp ]: classesPropTypeUtil.create( [ newId, ...currentUsedClasses.value ] ) },
75
+ withHistory: false,
76
+ } );
77
+ };
@@ -1,8 +1,9 @@
1
1
  import * as React from 'react';
2
- import { type ReactElement, useState } from 'react';
2
+ import { type ReactElement, useEffect, useState } from 'react';
3
3
  import { stylesRepository, useUserStylesCapability, validateStyleLabel } from '@elementor/editor-styles-repository';
4
4
  import { EditableField, EllipsisWithTooltip, useEditable } from '@elementor/editor-ui';
5
5
  import { DotsVerticalIcon } from '@elementor/icons';
6
+ import { useSessionStorage } from '@elementor/session';
6
7
  import {
7
8
  type AutocompleteRenderGetTagProps,
8
9
  bindTrigger,
@@ -10,6 +11,7 @@ import {
10
11
  type ChipOwnProps,
11
12
  Stack,
12
13
  type Theme,
14
+ ThemeProvider,
13
15
  Typography,
14
16
  UnstableChipGroup,
15
17
  usePopupState,
@@ -48,6 +50,10 @@ export function CssClassItem( props: CssClassItemProps ) {
48
50
 
49
51
  const { userCan } = useUserStylesCapability();
50
52
 
53
+ const [ convertedFromLocalId, , clearConvertedFromLocalId ] = useSessionStorage(
54
+ `last-converted-class-generated-name`
55
+ );
56
+
51
57
  const {
52
58
  ref,
53
59
  isEditing,
@@ -68,8 +74,17 @@ export function CssClassItem( props: CssClassItemProps ) {
68
74
 
69
75
  const isShowingState = isActive && meta.state;
70
76
 
77
+ useEffect( () => {
78
+ if ( convertedFromLocalId && id === convertedFromLocalId ) {
79
+ clearConvertedFromLocalId();
80
+ openEditMode();
81
+ }
82
+ // eslint-disable-next-line react-compiler/react-compiler
83
+ // eslint-disable-next-line react-hooks/exhaustive-deps
84
+ }, [ id ] );
85
+
71
86
  return (
72
- <>
87
+ <ThemeProvider palette="default">
73
88
  <UnstableChipGroup
74
89
  ref={ setChipRef }
75
90
  { ...chipGroupProps }
@@ -144,7 +159,7 @@ export function CssClassItem( props: CssClassItemProps ) {
144
159
  <CssClassProvider { ...classProps } handleRename={ openEditMode }>
145
160
  <CssClassMenu popupState={ popupState } anchorEl={ chipRef } fixed={ fixed } />
146
161
  </CssClassProvider>
147
- </>
162
+ </ThemeProvider>
148
163
  );
149
164
  }
150
165
 
@@ -1,15 +1,20 @@
1
1
  import * as React from 'react';
2
2
  import { type StyleDefinitionState } from '@elementor/editor-styles';
3
- import { stylesRepository, useUserStylesCapability } from '@elementor/editor-styles-repository';
3
+ import {
4
+ isElementsStylesProvider,
5
+ stylesRepository,
6
+ useUserStylesCapability,
7
+ } from '@elementor/editor-styles-repository';
4
8
  import { MenuItemInfotip, MenuListItem } from '@elementor/editor-ui';
5
9
  import { bindMenu, Divider, Menu, MenuSubheader, type PopupState, Stack } from '@elementor/ui';
6
10
  import { __ } from '@wordpress/i18n';
7
11
 
8
12
  import { useStyle } from '../../contexts/style-context';
9
13
  import { type StyleDefinitionStateWithNormal } from '../../styles-inheritance/types';
10
- import { getStylesProviderThemeColor } from '../../utils/get-styles-provider-color';
14
+ import { getTempStylesProviderThemeColor } from '../../utils/get-styles-provider-color';
11
15
  import { StyleIndicator } from '../style-indicator';
12
16
  import { useCssClass } from './css-class-context';
17
+ import { LocalClassSubMenu } from './local-class-sub-menu';
13
18
  import { useUnapplyClass } from './use-apply-and-unapply-class';
14
19
 
15
20
  type State = {
@@ -32,6 +37,7 @@ type CssClassMenuProps = {
32
37
 
33
38
  export function CssClassMenu( { popupState, anchorEl, fixed }: CssClassMenuProps ) {
34
39
  const { provider } = useCssClass();
40
+ const isLocalStyle = provider ? isElementsStylesProvider( provider ) : true;
35
41
 
36
42
  const handleKeyDown = ( e: React.KeyboardEvent< HTMLElement > ) => {
37
43
  e.stopPropagation();
@@ -54,6 +60,7 @@ export function CssClassMenu( { popupState, anchorEl, fixed }: CssClassMenuProps
54
60
  // Workaround for focus-visible issue.
55
61
  disableAutoFocusItem
56
62
  >
63
+ { isLocalStyle && <LocalClassSubMenu popupState={ popupState } /> }
57
64
  { /* 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 */ }
58
65
  { getMenuItemsByProvider( { provider, closeMenu: popupState.close, fixed } ) }
59
66
  <MenuSubheader sx={ { typography: 'caption', color: 'text.secondary', pb: 0.5, pt: 1 } }>
@@ -161,7 +168,7 @@ function StateMenuItem( { state, closeMenu, ...props }: StateMenuItemProps ) {
161
168
  { isStyled && (
162
169
  <StyleIndicator
163
170
  aria-label={ __( 'Has style', 'elementor' ) }
164
- getColor={ getStylesProviderThemeColor( provider ?? '' ) }
171
+ getColor={ getTempStylesProviderThemeColor( provider ?? '' ) }
165
172
  />
166
173
  ) }
167
174
  { state ?? 'normal' }
@@ -53,7 +53,7 @@ const EMPTY_OPTION = {
53
53
  label: __( 'local', 'elementor' ),
54
54
  value: null,
55
55
  fixed: true,
56
- color: 'accent',
56
+ color: getTempStylesProviderColorName( 'accent' ),
57
57
  icon: <MapPinIcon />,
58
58
  provider: null,
59
59
  } satisfies StyleDefOption;
@@ -221,7 +221,7 @@ function useOptions() {
221
221
  label: styleDef.label,
222
222
  value: styleDef.id,
223
223
  fixed: isElements,
224
- color: getStylesProviderColorName( provider.getKey() ),
224
+ color: getTempStylesProviderColorName( getStylesProviderColorName( provider.getKey() ) ),
225
225
  icon: isElements ? <MapPinIcon /> : null,
226
226
  provider: provider.getKey(),
227
227
  };
@@ -229,6 +229,14 @@ function useOptions() {
229
229
  } );
230
230
  }
231
231
 
232
+ function getTempStylesProviderColorName( color: ChipOwnProps[ 'color' ] ): ChipOwnProps[ 'color' ] {
233
+ if ( color === 'accent' ) {
234
+ return 'primary';
235
+ }
236
+
237
+ return color;
238
+ }
239
+
232
240
  function useCreateAction() {
233
241
  const [ provider, createAction ] = useCreateAndApplyClass();
234
242
  if ( ! provider || ! createAction ) {
@@ -0,0 +1,23 @@
1
+ import * as React from 'react';
2
+ import { MenuSubheader, type PopupState } from '@elementor/ui';
3
+ import { __ } from '@wordpress/i18n';
4
+
5
+ import { CssClassConvert } from './css-class-convert-local';
6
+ import { useCanConvertLocalClassToGlobal } from './use-can-convert-local-class-to-global';
7
+
8
+ type OwnProps = {
9
+ popupState: PopupState;
10
+ };
11
+
12
+ export const LocalClassSubMenu = ( props: OwnProps ) => {
13
+ const { canConvert, styleDef } = useCanConvertLocalClassToGlobal();
14
+
15
+ return (
16
+ <>
17
+ <MenuSubheader sx={ { typography: 'caption', color: 'text.secondary', pb: 0.5, pt: 1 } }>
18
+ { __( 'Local Class', 'elementor' ) }
19
+ </MenuSubheader>
20
+ <CssClassConvert canConvert={ canConvert } styleDef={ styleDef } closeMenu={ props.popupState.close } />
21
+ </>
22
+ );
23
+ };
@@ -4,13 +4,12 @@ import { getElementLabel, getElementSetting, updateElementSettings } from '@elem
4
4
  import { classesPropTypeUtil, type ClassesPropValue } from '@elementor/editor-props';
5
5
  import { type StyleDefinitionID } from '@elementor/editor-styles';
6
6
  import { useGetStylesRepositoryCreateAction } from '@elementor/editor-styles-repository';
7
- import { isExperimentActive, undoable } from '@elementor/editor-v1-adapters';
7
+ import { undoable } from '@elementor/editor-v1-adapters';
8
8
  import { __ } from '@wordpress/i18n';
9
9
 
10
10
  import { useClassesProp } from '../../contexts/classes-prop-context';
11
11
  import { useElement } from '../../contexts/element-context';
12
12
  import { useStyle } from '../../contexts/style-context';
13
- import { EXPERIMENTAL_FEATURES } from '../../sync/experiments-flags';
14
13
 
15
14
  type UndoableClassActionPayload = {
16
15
  classId: StyleDefinitionID;
@@ -30,12 +29,10 @@ export function useApplyClass() {
30
29
  const { id: activeId, setId: setActiveId } = useStyle();
31
30
  const { element } = useElement();
32
31
 
33
- const isVersion330Active = isExperimentActive( EXPERIMENTAL_FEATURES.V_3_30 );
34
-
35
32
  const applyClass = useApply();
36
33
  const unapplyClass = useUnapply();
37
34
 
38
- const undoableApply = useMemo( () => {
35
+ return useMemo( () => {
39
36
  return undoable(
40
37
  {
41
38
  do: ( { classId }: UndoableClassActionPayload ) => {
@@ -59,27 +56,16 @@ export function useApplyClass() {
59
56
  }
60
57
  );
61
58
  }, [ activeId, applyClass, element.id, unapplyClass, setActiveId ] );
62
-
63
- const applyWithoutHistory = useCallback(
64
- ( { classId }: UndoableClassActionPayload ) => {
65
- applyClass( classId );
66
- },
67
- [ applyClass ]
68
- );
69
-
70
- return isVersion330Active ? undoableApply : applyWithoutHistory;
71
59
  }
72
60
 
73
61
  export function useUnapplyClass() {
74
62
  const { id: activeId, setId: setActiveId } = useStyle();
75
63
  const { element } = useElement();
76
64
 
77
- const isVersion330Active = isExperimentActive( EXPERIMENTAL_FEATURES.V_3_30 );
78
-
79
65
  const applyClass = useApply();
80
66
  const unapplyClass = useUnapply();
81
67
 
82
- const undoableUnapply = useMemo( () => {
68
+ return useMemo( () => {
83
69
  return undoable(
84
70
  {
85
71
  do: ( { classId }: UndoableClassActionPayload ) => {
@@ -103,22 +89,11 @@ export function useUnapplyClass() {
103
89
  }
104
90
  );
105
91
  }, [ activeId, applyClass, element.id, unapplyClass, setActiveId ] );
106
-
107
- const unapplyWithoutHistory = useCallback(
108
- ( { classId }: UndoableClassActionPayload ) => {
109
- unapplyClass( classId );
110
- },
111
- [ unapplyClass ]
112
- );
113
-
114
- return isVersion330Active ? undoableUnapply : unapplyWithoutHistory;
115
92
  }
116
93
 
117
94
  export function useCreateAndApplyClass() {
118
95
  const { id: activeId, setId: setActiveId } = useStyle();
119
96
 
120
- const isVersion330Active = isExperimentActive( EXPERIMENTAL_FEATURES.V_3_30 );
121
-
122
97
  const [ provider, createAction ] = useGetStylesRepositoryCreateAction() ?? [ null, null ];
123
98
  const deleteAction = provider?.actions.delete;
124
99
 
@@ -157,25 +132,11 @@ export function useCreateAndApplyClass() {
157
132
  );
158
133
  }, [ activeId, applyClass, createAction, deleteAction, provider, setActiveId, unapplyClass ] );
159
134
 
160
- const createAndApplyWithoutHistory = useCallback(
161
- ( { classLabel }: CreateAndApplyClassPayload ) => {
162
- if ( ! createAction ) {
163
- return;
164
- }
165
-
166
- const createdId = createAction( classLabel );
167
- applyClass( createdId );
168
- },
169
- [ applyClass, createAction ]
170
- );
171
-
172
135
  if ( ! provider || ! undoableCreateAndApply ) {
173
136
  return [ null, null ];
174
137
  }
175
138
 
176
- return isVersion330Active
177
- ? ( [ provider, undoableCreateAndApply ] as const )
178
- : ( [ provider, createAndApplyWithoutHistory ] as const );
139
+ return [ provider, undoableCreateAndApply ] as const;
179
140
  }
180
141
 
181
142
  function useApply() {
@@ -231,24 +192,20 @@ function useClasses() {
231
192
  const { element } = useElement();
232
193
  const currentClassesProp = useClassesProp();
233
194
 
234
- const isVersion330Active = isExperimentActive( EXPERIMENTAL_FEATURES.V_3_30 );
235
-
236
195
  return useMemo( () => {
237
196
  const setClasses = ( ids: StyleDefinitionID[] ) => {
238
197
  updateElementSettings( {
239
198
  id: element.id,
240
199
  props: { [ currentClassesProp ]: classesPropTypeUtil.create( ids ) },
241
- withHistory: isVersion330Active ? false : true,
200
+ withHistory: false,
242
201
  } );
243
202
 
244
- if ( isVersion330Active ) {
245
- setDocumentModifiedStatus( true );
246
- }
203
+ setDocumentModifiedStatus( true );
247
204
  };
248
205
 
249
206
  const getAppliedClasses = () =>
250
207
  getElementSetting< ClassesPropValue >( element.id, currentClassesProp )?.value || [];
251
208
 
252
209
  return { setClasses, getAppliedClasses };
253
- }, [ currentClassesProp, element.id, isVersion330Active ] );
210
+ }, [ currentClassesProp, element.id ] );
254
211
  }
@@ -0,0 +1,22 @@
1
+ import { isElementsStylesProvider } from '@elementor/editor-styles-repository';
2
+
3
+ import { useElement } from '../../contexts/element-context';
4
+ import { useStyle } from '../../contexts/style-context';
5
+
6
+ export const useCanConvertLocalClassToGlobal = () => {
7
+ const { element } = useElement();
8
+ const { provider, id, meta } = useStyle();
9
+ const styleDef = provider?.actions.get( id, { elementId: element.id, ...meta } );
10
+
11
+ const isLocalStylesProvider = provider && isElementsStylesProvider( provider?.getKey() );
12
+ const variants = styleDef?.variants || [];
13
+
14
+ const canConvert = !! ( isLocalStylesProvider && variants.length );
15
+
16
+ return {
17
+ canConvert,
18
+ isLocalStylesProvider,
19
+ id,
20
+ styleDef: styleDef || null,
21
+ };
22
+ };
@@ -0,0 +1,21 @@
1
+ import * as React from 'react';
2
+ import { TextField } from '@elementor/ui';
3
+
4
+ import { useCustomCss } from '../hooks/use-custom-css';
5
+ import { SectionContent } from './section-content';
6
+
7
+ export const CustomCss = () => {
8
+ const { customCss, setCustomCss } = useCustomCss();
9
+
10
+ return (
11
+ <SectionContent>
12
+ <TextField
13
+ value={ customCss?.raw || '' }
14
+ onChange={ ( ev: React.ChangeEvent< HTMLInputElement > ) =>
15
+ setCustomCss( ev.target.value, { history: { propDisplayName: 'Custom CSS' } } )
16
+ }
17
+ multiline
18
+ />
19
+ </SectionContent>
20
+ );
21
+ };
@@ -1,6 +1,5 @@
1
1
  import * as React from 'react';
2
2
  import { Fragment } from 'react';
3
- import { isExperimentActive } from '@elementor/editor-v1-adapters';
4
3
  import { Divider, Stack, Tab, TabPanel, Tabs, useTabs } from '@elementor/ui';
5
4
  import { __ } from '@wordpress/i18n';
6
5
 
@@ -8,7 +7,6 @@ import { useElement } from '../contexts/element-context';
8
7
  import { ScrollProvider } from '../contexts/scroll-context';
9
8
  import { useDefaultPanelSettings } from '../hooks/use-default-panel-settings';
10
9
  import { useStateByElement } from '../hooks/use-state-by-element';
11
- import { EXPERIMENTAL_FEATURES } from '../sync/experiments-flags';
12
10
  import { SettingsTab } from './settings-tab';
13
11
  import { stickyHeaderStyles, StyleTab } from './style-tab';
14
12
 
@@ -27,9 +25,7 @@ export const EditingPanelTabs = () => {
27
25
 
28
26
  const PanelTabContent = () => {
29
27
  const editorDefaults = useDefaultPanelSettings();
30
- const defaultComponentTab = isExperimentActive( EXPERIMENTAL_FEATURES.V_3_30 )
31
- ? ( editorDefaults.defaultTab as TabValue )
32
- : 'settings';
28
+ const defaultComponentTab = editorDefaults.defaultTab as TabValue;
33
29
 
34
30
  const [ currentTab, setCurrentTab ] = useStateByElement< TabValue >( 'tab', defaultComponentTab );
35
31
  const { getTabProps, getTabPanelProps, getTabsProps } = useTabs< TabValue >( currentTab );
@@ -0,0 +1,12 @@
1
+ import * as React from 'react';
2
+ import { PopoverBody as BasePopoverBody } from '@elementor/editor-ui';
3
+
4
+ import { useSectionWidth } from '../contexts/section-context';
5
+
6
+ type Props = React.ComponentProps< typeof BasePopoverBody >;
7
+
8
+ export const PopoverBody = ( props: Props ) => {
9
+ const sectionWidth = useSectionWidth();
10
+
11
+ return <BasePopoverBody { ...props } width={ sectionWidth } />;
12
+ };
@@ -1,11 +1,9 @@
1
1
  import * as React from 'react';
2
2
  import { type PropsWithChildren, type ReactNode, useId, useRef } from 'react';
3
- import { isExperimentActive } from '@elementor/editor-v1-adapters';
4
3
  import { Collapse, Divider, ListItemButton, ListItemText, Stack } from '@elementor/ui';
5
4
 
6
5
  import { SectionRefContext } from '../contexts/section-context';
7
6
  import { useStateByElement } from '../hooks/use-state-by-element';
8
- import { EXPERIMENTAL_FEATURES } from '../sync/experiments-flags';
9
7
  import { CollapseIcon } from './collapse-icon';
10
8
  import { type CollapsibleValue, getCollapsibleValue } from './collapsible-content';
11
9
 
@@ -27,8 +25,6 @@ export function Section( { title, children, defaultExpanded = false, titleEnd }:
27
25
  const labelId = `label-${ id }`;
28
26
  const contentId = `content-${ id }`;
29
27
 
30
- const isUsingTitleEnd = isExperimentActive( EXPERIMENTAL_FEATURES.V_3_30 );
31
-
32
28
  return (
33
29
  <>
34
30
  <ListItemButton
@@ -43,7 +39,7 @@ export function Section( { title, children, defaultExpanded = false, titleEnd }:
43
39
  secondaryTypographyProps={ { color: 'text.primary', variant: 'caption', fontWeight: 'bold' } }
44
40
  sx={ { flexGrow: 0, flexShrink: 1, marginInlineEnd: 1 } }
45
41
  />
46
- { isUsingTitleEnd ? getCollapsibleValue( titleEnd, isOpen ) : null }
42
+ { getCollapsibleValue( titleEnd, isOpen ) }
47
43
  </Stack>
48
44
  <CollapseIcon open={ isOpen } color="secondary" fontSize="tiny" />
49
45
  </ListItemButton>
@@ -1,22 +1,15 @@
1
1
  import * as React from 'react';
2
2
  import { ControlFormLabel } from '@elementor/editor-controls';
3
3
  import { type Control } from '@elementor/editor-elements';
4
- import { isExperimentActive } from '@elementor/editor-v1-adapters';
5
4
  import { SessionStorageProvider } from '@elementor/session';
6
5
  import { Divider } from '@elementor/ui';
7
6
 
8
7
  import { useElement } from '../contexts/element-context';
9
8
  import { Control as BaseControl } from '../controls-registry/control';
10
9
  import { ControlTypeContainer } from '../controls-registry/control-type-container';
11
- import {
12
- type ControlType,
13
- getControl,
14
- getDefaultLayout,
15
- getPropTypeUtil,
16
- } from '../controls-registry/controls-registry';
10
+ import { controlsRegistry, type ControlType } from '../controls-registry/controls-registry';
17
11
  import { SettingsField } from '../controls-registry/settings-field';
18
12
  import { useDefaultPanelSettings } from '../hooks/use-default-panel-settings';
19
- import { EXPERIMENTAL_FEATURES } from '../sync/experiments-flags';
20
13
  import { Section } from './section';
21
14
  import { SectionsList } from './sections-list';
22
15
 
@@ -25,9 +18,7 @@ export const SettingsTab = () => {
25
18
  const settingsDefault = useDefaultPanelSettings();
26
19
 
27
20
  const isDefaultExpanded = ( sectionId: string ) =>
28
- isExperimentActive( EXPERIMENTAL_FEATURES.V_3_30 )
29
- ? settingsDefault.defaultSectionsExpanded.settings?.includes( sectionId )
30
- : true;
21
+ settingsDefault.defaultSectionsExpanded.settings?.includes( sectionId );
31
22
 
32
23
  return (
33
24
  <SessionStorageProvider prefix={ element.id }>
@@ -64,11 +55,11 @@ export const SettingsTab = () => {
64
55
  };
65
56
 
66
57
  const Control = ( { control }: { control: Control[ 'value' ] } ) => {
67
- if ( ! getControl( control.type as ControlType ) ) {
58
+ if ( ! controlsRegistry.get( control.type as ControlType ) ) {
68
59
  return null;
69
60
  }
70
61
 
71
- const layout = control.meta?.layout || getDefaultLayout( control.type as ControlType );
62
+ const layout = control.meta?.layout || controlsRegistry.getLayout( control.type as ControlType );
72
63
  const controlProps = populateChildControlProps( control.props );
73
64
  if ( layout === 'custom' ) {
74
65
  controlProps.label = control.label;
@@ -87,8 +78,8 @@ const Control = ( { control }: { control: Control[ 'value' ] } ) => {
87
78
 
88
79
  function populateChildControlProps( props: Record< string, unknown > ) {
89
80
  if ( props.childControlType ) {
90
- const childComponent = getControl( props.childControlType as ControlType );
91
- const childPropType = getPropTypeUtil( props.childControlType as ControlType );
81
+ const childComponent = controlsRegistry.get( props.childControlType as ControlType );
82
+ const childPropType = controlsRegistry.getPropTypeUtil( props.childControlType as ControlType );
92
83
  props = {
93
84
  ...props,
94
85
  childControlConfig: {