@elementor/editor-editing-panel 1.46.0 → 1.47.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 (68) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/dist/index.d.mts +12 -1
  3. package/dist/index.d.ts +12 -1
  4. package/dist/index.js +875 -753
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +787 -667
  7. package/dist/index.mjs.map +1 -1
  8. package/package.json +15 -15
  9. package/src/components/popover-scrollable-content.tsx +12 -0
  10. package/src/components/section-content.tsx +6 -16
  11. package/src/components/section.tsx +8 -4
  12. package/src/components/settings-tab.tsx +5 -2
  13. package/src/components/style-sections/background-section/background-section.tsx +4 -1
  14. package/src/components/style-sections/border-section/border-color-field.tsx +10 -16
  15. package/src/components/style-sections/border-section/border-radius-field.tsx +4 -2
  16. package/src/components/style-sections/border-section/border-style-field.tsx +11 -16
  17. package/src/components/style-sections/border-section/border-width-field.tsx +4 -2
  18. package/src/components/style-sections/effects-section/effects-section.tsx +19 -5
  19. package/src/components/style-sections/layout-section/align-content-field.tsx +11 -12
  20. package/src/components/style-sections/layout-section/align-items-field.tsx +8 -11
  21. package/src/components/style-sections/layout-section/align-self-child-field.tsx +11 -16
  22. package/src/components/style-sections/layout-section/display-field.tsx +6 -6
  23. package/src/components/style-sections/layout-section/flex-direction-field.tsx +11 -14
  24. package/src/components/style-sections/layout-section/flex-order-field.tsx +31 -34
  25. package/src/components/style-sections/layout-section/flex-size-field.tsx +28 -48
  26. package/src/components/style-sections/layout-section/gap-control-field.tsx +5 -6
  27. package/src/components/style-sections/layout-section/justify-content-field.tsx +11 -12
  28. package/src/components/style-sections/layout-section/opacity-control-field.tsx +9 -13
  29. package/src/components/style-sections/layout-section/wrap-field.tsx +10 -14
  30. package/src/components/style-sections/position-section/dimensions-field.tsx +4 -4
  31. package/src/components/style-sections/position-section/offset-field.tsx +12 -14
  32. package/src/components/style-sections/position-section/position-field.tsx +7 -11
  33. package/src/components/style-sections/position-section/z-index-field.tsx +7 -11
  34. package/src/components/style-sections/size-section/object-fit-field.tsx +7 -11
  35. package/src/components/style-sections/size-section/object-position-field.tsx +4 -1
  36. package/src/components/style-sections/size-section/overflow-field.tsx +7 -11
  37. package/src/components/style-sections/size-section/size-section.tsx +9 -7
  38. package/src/components/style-sections/spacing-section/spacing-section.tsx +7 -4
  39. package/src/components/style-sections/typography-section/column-count-field.tsx +7 -11
  40. package/src/components/style-sections/typography-section/column-gap-field.tsx +9 -13
  41. package/src/components/style-sections/typography-section/font-family-field.tsx +9 -11
  42. package/src/components/style-sections/typography-section/font-size-field.tsx +9 -13
  43. package/src/components/style-sections/typography-section/font-style-field.tsx +13 -13
  44. package/src/components/style-sections/typography-section/font-weight-field.tsx +7 -11
  45. package/src/components/style-sections/typography-section/letter-spacing-field.tsx +9 -13
  46. package/src/components/style-sections/typography-section/line-height-field.tsx +9 -13
  47. package/src/components/style-sections/typography-section/text-alignment-field.tsx +11 -14
  48. package/src/components/style-sections/typography-section/text-color-field.tsx +7 -11
  49. package/src/components/style-sections/typography-section/text-decoration-field.tsx +7 -11
  50. package/src/components/style-sections/typography-section/text-direction-field.tsx +7 -11
  51. package/src/components/style-sections/typography-section/text-stroke-field.tsx +4 -2
  52. package/src/components/style-sections/typography-section/transform-field.tsx +7 -11
  53. package/src/components/style-sections/typography-section/word-spacing-field.tsx +9 -13
  54. package/src/components/styles-field-layout.tsx +50 -0
  55. package/src/contexts/section-context.tsx +14 -0
  56. package/src/controls-registry/control-type-container.tsx +6 -2
  57. package/src/controls-registry/controls-registry.tsx +1 -1
  58. package/src/controls-registry/settings-field.tsx +65 -6
  59. package/src/controls-registry/styles-field.tsx +10 -2
  60. package/src/dynamics/components/dynamic-selection-control.tsx +10 -4
  61. package/src/dynamics/components/dynamic-selection.tsx +18 -14
  62. package/src/hooks/use-default-panel-settings.ts +4 -0
  63. package/src/index.ts +4 -0
  64. package/src/popover-action.tsx +8 -1
  65. package/src/styles-inheritance/components/styles-inheritance-indicator.tsx +4 -1
  66. package/src/styles-inheritance/components/styles-inheritance-infotip.tsx +9 -19
  67. package/src/sync/experiments-flags.ts +1 -0
  68. package/src/components/popover-content.tsx +0 -15
@@ -1,17 +1,29 @@
1
1
  import * as React from 'react';
2
+ import { useMemo } from 'react';
2
3
  import { PropKeyProvider, PropProvider } from '@elementor/editor-controls';
3
- import { updateElementSettings, useElementSetting } from '@elementor/editor-elements';
4
+ import { setDocumentModifiedStatus } from '@elementor/editor-documents';
5
+ import {
6
+ type ElementID,
7
+ getElementLabel,
8
+ getElementSetting,
9
+ updateElementSettings,
10
+ useElementSetting,
11
+ } from '@elementor/editor-elements';
4
12
  import { type PropKey, type PropValue } from '@elementor/editor-props';
13
+ import { isExperimentActive, undoable } from '@elementor/editor-v1-adapters';
14
+ import { __ } from '@wordpress/i18n';
5
15
 
6
16
  import { useElement } from '../contexts/element-context';
17
+ import { EXPERIMENTAL_FEATURES } from '../sync/experiments-flags';
7
18
  import { createTopLevelOjectType } from './create-top-level-object-type';
8
19
 
9
20
  type Props = {
10
21
  bind: PropKey;
22
+ propDisplayName: string;
11
23
  children: React.ReactNode;
12
24
  };
13
25
 
14
- export const SettingsField = ( { bind, children }: Props ) => {
26
+ export const SettingsField = ( { bind, children, propDisplayName }: Props ) => {
15
27
  const { element, elementType } = useElement();
16
28
 
17
29
  const settingsValue = useElementSetting< PropValue >( element.id, bind );
@@ -20,11 +32,20 @@ export const SettingsField = ( { bind, children }: Props ) => {
20
32
 
21
33
  const propType = createTopLevelOjectType( { schema: elementType.propsSchema } );
22
34
 
35
+ const undoableUpdateElementProp = useUndoableUpdateElementProp( {
36
+ propKey: bind,
37
+ elementId: element.id,
38
+ propDisplayName,
39
+ } );
40
+
23
41
  const setValue = ( newValue: Record< string, PropValue > ) => {
24
- updateElementSettings( {
25
- id: element.id,
26
- props: { ...newValue },
27
- } );
42
+ const isVersion331Active = isExperimentActive( EXPERIMENTAL_FEATURES.V_3_31 );
43
+
44
+ if ( isVersion331Active ) {
45
+ undoableUpdateElementProp( { newValue } );
46
+ } else {
47
+ updateElementSettings( { id: element.id, props: newValue } );
48
+ }
28
49
  };
29
50
 
30
51
  return (
@@ -33,3 +54,41 @@ export const SettingsField = ( { bind, children }: Props ) => {
33
54
  </PropProvider>
34
55
  );
35
56
  };
57
+
58
+ type UndoableUpdateElementSettingsArgs = {
59
+ newValue: Record< string, PropValue >;
60
+ };
61
+
62
+ function useUndoableUpdateElementProp( {
63
+ propKey,
64
+ elementId,
65
+ propDisplayName,
66
+ }: {
67
+ propKey: PropKey;
68
+ elementId: ElementID;
69
+ propDisplayName: string;
70
+ } ) {
71
+ return useMemo( () => {
72
+ return undoable(
73
+ {
74
+ do: ( { newValue }: UndoableUpdateElementSettingsArgs ) => {
75
+ const prevPropValue = getElementSetting( elementId, propKey ) as PropValue;
76
+
77
+ updateElementSettings( { id: elementId, props: { ...newValue }, withHistory: false } );
78
+ setDocumentModifiedStatus( true );
79
+
80
+ return { [ propKey ]: prevPropValue };
81
+ },
82
+
83
+ undo: ( {}, prevProps ) => {
84
+ updateElementSettings( { id: elementId, props: prevProps, withHistory: false } );
85
+ },
86
+ },
87
+ {
88
+ title: getElementLabel( elementId ),
89
+ // translators: %s is the name of the property that was edited.
90
+ subtitle: __( '%s edited', 'elementor' ).replace( '%s', propDisplayName ),
91
+ }
92
+ );
93
+ }, [ propKey, elementId, propDisplayName ] );
94
+ }
@@ -2,7 +2,9 @@ import * as React from 'react';
2
2
  import { ControlAdornmentsProvider, PropKeyProvider, PropProvider } from '@elementor/editor-controls';
3
3
  import { type PropKey, type PropValue } from '@elementor/editor-props';
4
4
  import { getStylesSchema } from '@elementor/editor-styles';
5
+ import { isExperimentActive } from '@elementor/editor-v1-adapters';
5
6
 
7
+ import { useStylesInheritanceChain } from '../contexts/styles-inheritance-context';
6
8
  import { useStylesField } from '../hooks/use-styles-field';
7
9
  import { StylesInheritanceIndicator } from '../styles-inheritance/components/styles-inheritance-indicator';
8
10
  import { createTopLevelOjectType } from './create-top-level-object-type';
@@ -11,18 +13,24 @@ export type StylesFieldProps = {
11
13
  bind: PropKey;
12
14
  placeholder?: PropValue;
13
15
  children: React.ReactNode;
16
+ propDisplayName: string;
14
17
  };
15
18
 
16
19
  export const StylesField = ( { bind, placeholder, children }: StylesFieldProps ) => {
17
20
  const { value, setValue, canEdit } = useStylesField( bind );
18
21
 
22
+ const isVersion331Active = isExperimentActive( 'e_v_3_31' );
23
+ const stylesInheritanceChain = useStylesInheritanceChain( [ bind ] );
24
+
19
25
  const stylesSchema = getStylesSchema();
20
26
 
21
27
  const propType = createTopLevelOjectType( { schema: stylesSchema } );
22
28
 
23
29
  const values = { [ bind ]: value };
24
- const placeholderValues = { [ bind ]: placeholder };
25
-
30
+ const [ actualValue ] = stylesInheritanceChain;
31
+ const placeholderValues = {
32
+ [ bind ]: isVersion331Active ? actualValue?.value : placeholder,
33
+ };
26
34
  const setValues = ( newValue: Record< string, PropValue > ) => {
27
35
  setValue( newValue[ bind ] );
28
36
  };
@@ -21,7 +21,6 @@ import {
21
21
  } from '@elementor/ui';
22
22
  import { __ } from '@wordpress/i18n';
23
23
 
24
- import { PopoverContent } from '../../components/popover-content';
25
24
  import { Control as BaseControl } from '../../controls-registry/control';
26
25
  import { type ControlType, getControl } from '../../controls-registry/controls-registry';
27
26
  import { usePersistDynamicValue } from '../../hooks/use-persist-dynamic-value';
@@ -76,7 +75,11 @@ export const DynamicSelectionControl = () => {
76
75
  <Popover
77
76
  disablePortal
78
77
  disableScrollLock
79
- anchorOrigin={ { vertical: 'bottom', horizontal: 'left' } }
78
+ anchorOrigin={ { vertical: 'bottom', horizontal: 'right' } }
79
+ transformOrigin={ { vertical: 'top', horizontal: 'right' } }
80
+ PaperProps={ {
81
+ sx: { my: 1 },
82
+ } }
80
83
  { ...bindPopover( selectionPopoverState ) }
81
84
  >
82
85
  <Stack>
@@ -105,6 +108,9 @@ export const DynamicSettingsPopover = ( { dynamicTag }: { dynamicTag: DynamicTag
105
108
  disablePortal
106
109
  disableScrollLock
107
110
  anchorOrigin={ { vertical: 'bottom', horizontal: 'center' } }
111
+ PaperProps={ {
112
+ sx: { my: 0.5 },
113
+ } }
108
114
  { ...bindPopover( popupState ) }
109
115
  >
110
116
  <PopoverHeader
@@ -139,14 +145,14 @@ const DynamicSettings = ( { controls }: { controls: DynamicTag[ 'atomic_controls
139
145
  { tabs.map( ( { value }, index ) => {
140
146
  return (
141
147
  <TabPanel key={ index } sx={ { flexGrow: 1, py: 0 } } { ...getTabPanelProps( index ) }>
142
- <PopoverContent p={ 2 } gap={ 2 }>
148
+ <Stack p={ 2 } gap={ 2 }>
143
149
  { value.items.map( ( item ) => {
144
150
  if ( item.type === 'control' ) {
145
151
  return <Control key={ item.value.bind } control={ item.value } />;
146
152
  }
147
153
  return null;
148
154
  } ) }
149
- </PopoverContent>
155
+ </Stack>
150
156
  </TabPanel>
151
157
  );
152
158
  } ) }
@@ -6,6 +6,7 @@ import { DatabaseIcon } from '@elementor/icons';
6
6
  import { Box, Divider, Link, Stack, Typography, useTheme } from '@elementor/ui';
7
7
  import { __ } from '@wordpress/i18n';
8
8
 
9
+ import { PopoverScrollableContent } from '../../components/popover-scrollable-content';
9
10
  import { usePersistDynamicValue } from '../../hooks/use-persist-dynamic-value';
10
11
  import { usePropDynamicTags } from '../hooks/use-prop-dynamic-tags';
11
12
  import { getAtomicDynamicTags } from '../sync/get-atomic-dynamic-tags';
@@ -91,19 +92,23 @@ export const DynamicSelection = ( { close: closePopover }: DynamicSelectionProps
91
92
  onSearch={ handleSearch }
92
93
  placeholder={ __( 'Search dynamic tags…', 'elementor' ) }
93
94
  />
95
+
94
96
  <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
- />
97
+
98
+ <PopoverScrollableContent>
99
+ <PopoverMenuList
100
+ items={ virtualizedItems }
101
+ onSelect={ handleSetDynamicTag }
102
+ onClose={ closePopover }
103
+ selectedValue={ dynamicValue?.name }
104
+ itemStyle={ ( item ) =>
105
+ item.type === 'item' ? { paddingInlineStart: theme.spacing( 3.5 ) } : {}
106
+ }
107
+ noResultsComponent={
108
+ <NoResults searchValue={ searchValue } onClear={ () => setSearchValue( '' ) } />
109
+ }
110
+ />
111
+ </PopoverScrollableContent>
107
112
  </Fragment>
108
113
  ) }
109
114
  </Stack>
@@ -127,9 +132,8 @@ const NoResults = ( { searchValue, onClear }: NoResultsProps ) => (
127
132
  <br />
128
133
  &ldquo;{ searchValue }&rdquo;.
129
134
  </Typography>
130
- <Typography align="center" variant="caption">
135
+ <Typography align="center" variant="caption" sx={ { display: 'flex', flexDirection: 'column' } }>
131
136
  { __( 'Try something else.', 'elementor' ) }
132
- &nbsp;
133
137
  <Link color="text.secondary" variant="caption" component="button" onClick={ onClear }>
134
138
  { __( 'Clear & try again', 'elementor' ) }
135
139
  </Link>
@@ -24,6 +24,10 @@ const defaultPanelSettingsContext = createContext< Record< string, Defaults | un
24
24
  defaultSectionsExpanded: fallbackEditorSettings.defaultSectionsExpanded,
25
25
  defaultTab: 'style',
26
26
  },
27
+ 'e-divider': {
28
+ defaultSectionsExpanded: fallbackEditorSettings.defaultSectionsExpanded,
29
+ defaultTab: 'style',
30
+ },
27
31
  } );
28
32
 
29
33
  export const useDefaultPanelSettings = () => {
package/src/index.ts CHANGED
@@ -1,3 +1,5 @@
1
+ export { EXPERIMENTAL_FEATURES } from './sync/experiments-flags';
2
+
1
3
  export { useBoundProp } from '@elementor/editor-controls';
2
4
  export type { PopoverActionProps } from './popover-action';
3
5
  export { registerControlReplacement } from './control-replacement';
@@ -7,5 +9,7 @@ export { usePanelActions, usePanelStatus } from './panel';
7
9
  export { type ValidationResult, type ValidationEvent } from './components/creatable-autocomplete';
8
10
  export { controlActionsMenu } from './controls-actions';
9
11
  export { useFontFamilies } from './components/style-sections/typography-section/hooks/use-font-families';
12
+ export { PopoverScrollableContent } from './components/popover-scrollable-content';
13
+ export { useSectionWidth } from './contexts/section-context';
10
14
 
11
15
  export { init } from './init';
@@ -39,7 +39,14 @@ export default function PopoverAction( {
39
39
  disableScrollLock
40
40
  anchorOrigin={ {
41
41
  vertical: 'bottom',
42
- horizontal: 'center',
42
+ horizontal: 'right',
43
+ } }
44
+ transformOrigin={ {
45
+ vertical: 'top',
46
+ horizontal: 'right',
47
+ } }
48
+ PaperProps={ {
49
+ sx: { my: 2.5 },
43
50
  } }
44
51
  { ...bindPopover( popupState ) }
45
52
  >
@@ -50,7 +50,10 @@ const Indicator = ( { inheritanceChain, path, propType }: IndicatorProps ) => {
50
50
 
51
51
  const [ actualStyle ] = inheritanceChain;
52
52
 
53
- if ( actualStyle.provider === ELEMENTS_BASE_STYLES_PROVIDER_KEY ) {
53
+ if (
54
+ ! isExperimentActive( EXPERIMENTAL_FEATURES.V_3_31 ) &&
55
+ actualStyle.provider === ELEMENTS_BASE_STYLES_PROVIDER_KEY
56
+ ) {
54
57
  return null;
55
58
  }
56
59
 
@@ -2,29 +2,30 @@ import * as React from 'react';
2
2
  import { useMemo, useState } from 'react';
3
3
  import { createPropsResolver, type PropsResolver } from '@elementor/editor-canvas';
4
4
  import { type PropKey, type PropType } from '@elementor/editor-props';
5
+ import { PopoverHeader } from '@elementor/editor-ui';
5
6
  import {
6
7
  Backdrop,
7
8
  Box,
8
9
  Card,
9
10
  CardContent,
10
11
  ClickAwayListener,
11
- CloseButton,
12
12
  IconButton,
13
13
  Infotip,
14
14
  Stack,
15
15
  type Theme,
16
16
  Tooltip,
17
- Typography,
18
17
  } from '@elementor/ui';
19
18
  import { __ } from '@wordpress/i18n';
20
19
 
21
- import { useSectionContentRef } from '../../components/section-content';
20
+ import { useSectionWidth } from '../../contexts/section-context';
22
21
  import { useDirection } from '../../hooks/use-direction';
23
22
  import { useNormalizedInheritanceChainItems } from '../hooks/use-normalized-inheritance-chain-items';
24
23
  import { stylesInheritanceTransformersRegistry } from '../styles-inheritance-transformers-registry';
25
24
  import { type SnapshotPropValue } from '../types';
26
25
  import { ActionIcons, BreakpointIcon, LabelChip, ValueComponent } from './infotip';
27
26
 
27
+ const SECTION_PADDING_INLINE = 32;
28
+
28
29
  type Props = {
29
30
  inheritanceChain: SnapshotPropValue[];
30
31
  propType: PropType;
@@ -33,8 +34,6 @@ type Props = {
33
34
  children: React.ReactNode;
34
35
  };
35
36
 
36
- const SIZE = 'tiny';
37
-
38
37
  export const StylesInheritanceInfotip = ( { inheritanceChain, propType, path, label, children }: Props ) => {
39
38
  const [ showInfotip, setShowInfotip ] = useState< boolean >( false );
40
39
  const toggleInfotip = () => setShowInfotip( ( prev ) => ! prev );
@@ -42,8 +41,7 @@ export const StylesInheritanceInfotip = ( { inheritanceChain, propType, path, la
42
41
 
43
42
  const key = path.join( '.' );
44
43
 
45
- const sectionContentRef = useSectionContentRef();
46
- const sectionContentWidth = sectionContentRef?.current?.offsetWidth ?? 320;
44
+ const sectionWidth = useSectionWidth() + SECTION_PADDING_INLINE;
47
45
 
48
46
  const resolve = useMemo< PropsResolver >( () => {
49
47
  return createPropsResolver( {
@@ -59,8 +57,8 @@ export const StylesInheritanceInfotip = ( { inheritanceChain, propType, path, la
59
57
  <Card
60
58
  elevation={ 0 }
61
59
  sx={ {
62
- width: `${ sectionContentWidth }px`,
63
- maxWidth: 500,
60
+ width: `${ sectionWidth - SECTION_PADDING_INLINE }px`,
61
+ maxWidth: 496,
64
62
  overflowX: 'hidden',
65
63
  } }
66
64
  >
@@ -75,16 +73,8 @@ export const StylesInheritanceInfotip = ( { inheritanceChain, propType, path, la
75
73
  },
76
74
  } }
77
75
  >
78
- <Stack direction="row" alignItems="center" sx={ { pl: 1.5, pr: 0.5, minHeight: 36, py: 0.5 } }>
79
- <Typography variant="subtitle2" color="secondary" sx={ { fontSize: 12, fontWeight: '500' } }>
80
- { __( 'Style origin', 'elementor' ) }
81
- </Typography>
82
- <CloseButton
83
- slotProps={ { icon: { fontSize: SIZE } } }
84
- sx={ { ml: 'auto' } }
85
- onClick={ closeInfotip }
86
- />
87
- </Stack>
76
+ <PopoverHeader title={ __( 'Style origin', 'elementor' ) } onClose={ closeInfotip } />
77
+
88
78
  <Stack
89
79
  gap={ 1.5 }
90
80
  sx={ { pl: 2, pr: 1, pb: 2, overflowX: 'hidden', overflowY: 'auto' } }
@@ -1,4 +1,5 @@
1
1
  // Experimental features flags
2
2
  export const EXPERIMENTAL_FEATURES = {
3
3
  V_3_30: 'e_v_3_30',
4
+ V_3_31: 'e_v_3_31',
4
5
  };
@@ -1,15 +0,0 @@
1
- import { type FC, type PropsWithChildren } from 'react';
2
- import * as React from 'react';
3
- import { Stack } from '@elementor/ui';
4
-
5
- type PopoverContentProps = PropsWithChildren< {
6
- alignItems?: 'center';
7
- gap?: number;
8
- p?: 1.5 | 2 | 2.5;
9
- } >;
10
-
11
- export const PopoverContent: FC< PopoverContentProps > = ( { alignItems, gap = 1.5, p, children } ) => (
12
- <Stack alignItems={ alignItems } gap={ gap } p={ p }>
13
- { children }
14
- </Stack>
15
- );