@elementor/editor-editing-panel 1.17.0 → 1.18.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.
@@ -1,98 +1,49 @@
1
1
  import * as React from 'react';
2
- import { ControlLabel } from '@elementor/editor-controls';
3
- import { type StringPropValue } from '@elementor/editor-props';
4
- import { StrikethroughIcon, UnderlineIcon } from '@elementor/icons';
5
- import { Grid, ToggleButton as ToggleButtonBase, ToggleButtonGroup, type ToggleButtonProps } from '@elementor/ui';
2
+ import { ControlLabel, ToggleControl, type ToggleControlProps } from '@elementor/editor-controls';
3
+ import { MinusIcon, OverlineIcon, StrikethroughIcon, UnderlineIcon } from '@elementor/icons';
4
+ import { Grid } from '@elementor/ui';
6
5
  import { __ } from '@wordpress/i18n';
7
6
 
8
- import { useStylesField } from '../../../hooks/use-styles-field';
9
-
10
- const buttonSize = 'tiny';
11
-
12
- export const TextDecorationField = () => {
13
- const [ textDecoration, setTextDecoration ] = useStylesField< StringPropValue | null >( 'text-decoration' );
14
-
15
- const formats = [ ...( textDecoration?.value || '' ).split( ' ' ) ];
16
- const handleSetTextDecoration = ( newValue: string | null ) => {
17
- if ( newValue === null ) {
18
- return setTextDecoration( null );
19
- }
20
-
21
- setTextDecoration( {
22
- $$type: 'string',
23
- value: newValue,
24
- } );
25
- };
26
-
27
- return (
7
+ import { StylesField } from '../../../controls-registry/styles-field';
8
+
9
+ type Decoration = 'none' | 'underline' | 'line-through' | 'overline';
10
+
11
+ const options: ToggleControlProps< Decoration >[ 'options' ] = [
12
+ {
13
+ value: 'none',
14
+ label: __( 'None', 'elementor' ),
15
+ renderContent: ( { size } ) => <MinusIcon fontSize={ size } />,
16
+ showTooltip: true,
17
+ exclusive: true,
18
+ },
19
+ {
20
+ value: 'underline',
21
+ label: __( 'Underline', 'elementor' ),
22
+ renderContent: ( { size } ) => <UnderlineIcon fontSize={ size } />,
23
+ showTooltip: true,
24
+ },
25
+ {
26
+ value: 'line-through',
27
+ label: __( 'Line-through', 'elementor' ),
28
+ renderContent: ( { size } ) => <StrikethroughIcon fontSize={ size } />,
29
+ showTooltip: true,
30
+ },
31
+ {
32
+ value: 'overline',
33
+ label: __( 'Overline', 'elementor' ),
34
+ renderContent: ( { size } ) => <OverlineIcon fontSize={ size } />,
35
+ showTooltip: true,
36
+ },
37
+ ];
38
+ export const TextDecorationField = () => (
39
+ <StylesField bind={ 'text-decoration' }>
28
40
  <Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
29
41
  <Grid item xs={ 6 }>
30
- <ControlLabel>{ __( 'Style', 'elementor' ) }</ControlLabel>
42
+ <ControlLabel>{ __( 'Line decoration', 'elementor' ) }</ControlLabel>
31
43
  </Grid>
32
44
  <Grid item xs={ 6 } display="flex" justifyContent="end">
33
- <ToggleButtonGroup value={ formats }>
34
- <ShorthandControl
35
- value="line-through"
36
- currentValues={ textDecoration?.value || '' }
37
- updateValues={ handleSetTextDecoration }
38
- aria-label="line-through"
39
- >
40
- <StrikethroughIcon fontSize={ buttonSize } />
41
- </ShorthandControl>
42
- <ShorthandControl
43
- value="underline"
44
- currentValues={ textDecoration?.value || '' }
45
- updateValues={ handleSetTextDecoration }
46
- aria-label="underline"
47
- >
48
- <UnderlineIcon fontSize={ buttonSize } />
49
- </ShorthandControl>
50
- </ToggleButtonGroup>
45
+ <ToggleControl options={ options } exclusive={ false } />
51
46
  </Grid>
52
47
  </Grid>
53
- );
54
- };
55
-
56
- type ShorthandControlProps = React.PropsWithChildren< {
57
- value: string;
58
- currentValues: string;
59
- updateValues: ( newValue: string | null ) => void;
60
- 'aria-label': string;
61
- } >;
62
-
63
- export const ShorthandControl = ( {
64
- children,
65
- value,
66
- currentValues,
67
- updateValues,
68
- 'aria-label': ariaLabel,
69
- }: ShorthandControlProps ) => {
70
- const valuesArr = currentValues.split( ' ' ).filter( Boolean );
71
- const selected = valuesArr.includes( value );
72
-
73
- const toggleValue = ( newValue: string ) => {
74
- if ( selected ) {
75
- updateValues( valuesArr.filter( ( v ) => v !== newValue ).join( ' ' ) || null );
76
- } else {
77
- updateValues( [ ...valuesArr, newValue ].join( ' ' ) );
78
- }
79
- };
80
-
81
- return (
82
- <ToggleButton value={ value } onChange={ toggleValue } selected={ selected } aria-label={ ariaLabel }>
83
- { children }
84
- </ToggleButton>
85
- );
86
- };
87
-
88
- type ControlToggleButtonProps = Omit< ToggleButtonProps, 'onChange' > & {
89
- onChange: ( newValue: string ) => void;
90
- };
91
-
92
- const ToggleButton = ( { onChange, ...props }: ControlToggleButtonProps ) => {
93
- const handleChange = ( _e: React.MouseEvent< HTMLElement >, newValue: string ) => {
94
- onChange( newValue );
95
- };
96
-
97
- return <ToggleButtonBase { ...props } onChange={ handleChange } size={ buttonSize } />;
98
- };
48
+ </StylesField>
49
+ );
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { useState } from 'react';
3
- import { useElementSetting, useElementStyles } from '@elementor/editor-elements';
4
- import { type ClassesPropValue, type PropKey } from '@elementor/editor-props';
3
+ import { getElementStyles, useElementSetting } from '@elementor/editor-elements';
4
+ import { CLASSES_PROP_KEY, type ClassesPropValue, type PropKey } from '@elementor/editor-props';
5
5
  import { useActiveBreakpoint } from '@elementor/editor-responsive';
6
6
  import { type StyleDefinitionID, type StyleDefinitionState } from '@elementor/editor-styles';
7
7
  import { SessionStorageProvider } from '@elementor/session';
@@ -11,6 +11,7 @@ import { __ } from '@wordpress/i18n';
11
11
  import { ClassesPropProvider } from '../contexts/classes-prop-context';
12
12
  import { useElement } from '../contexts/element-context';
13
13
  import { StyleProvider } from '../contexts/style-context';
14
+ import { StyleInheritanceProvider } from '../contexts/styles-inheritance-context';
14
15
  import { CssClassSelector } from './css-classes/css-class-selector';
15
16
  import { Section } from './section';
16
17
  import { SectionsList } from './sections-list';
@@ -23,8 +24,6 @@ import { SizeSection } from './style-sections/size-section/size-section';
23
24
  import { SpacingSection } from './style-sections/spacing-section/spacing-section';
24
25
  import { TypographySection } from './style-sections/typography-section/typography-section';
25
26
 
26
- const CLASSES_PROP_KEY = 'classes';
27
-
28
27
  export const StyleTab = () => {
29
28
  const currentClassesProp = useCurrentClassesProp();
30
29
  const [ activeStyleDefId, setActiveStyleDefId ] = useActiveStyleDefId( currentClassesProp );
@@ -43,34 +42,36 @@ export const StyleTab = () => {
43
42
  setMetaState={ setActiveStyleState }
44
43
  >
45
44
  <SessionStorageProvider prefix={ activeStyleDefId ?? '' }>
46
- <CssClassSelector />
47
- <Divider />
48
- <SectionsList>
49
- <Section title={ __( 'Layout', 'elementor' ) }>
50
- <LayoutSection />
51
- </Section>
52
- <Section title={ __( 'Spacing', 'elementor' ) }>
53
- <SpacingSection />
54
- </Section>
55
- <Section title={ __( 'Size', 'elementor' ) }>
56
- <SizeSection />
57
- </Section>
58
- <Section title={ __( 'Position', 'elementor' ) }>
59
- <PositionSection />
60
- </Section>
61
- <Section title={ __( 'Typography', 'elementor' ) }>
62
- <TypographySection />
63
- </Section>
64
- <Section title={ __( 'Background', 'elementor' ) }>
65
- <BackgroundSection />
66
- </Section>
67
- <Section title={ __( 'Border', 'elementor' ) }>
68
- <BorderSection />
69
- </Section>
70
- <Section title={ __( 'Effects', 'elementor' ) }>
71
- <EffectsSection />
72
- </Section>
73
- </SectionsList>
45
+ <StyleInheritanceProvider>
46
+ <CssClassSelector />
47
+ <Divider />
48
+ <SectionsList>
49
+ <Section title={ __( 'Layout', 'elementor' ) }>
50
+ <LayoutSection />
51
+ </Section>
52
+ <Section title={ __( 'Spacing', 'elementor' ) }>
53
+ <SpacingSection />
54
+ </Section>
55
+ <Section title={ __( 'Size', 'elementor' ) }>
56
+ <SizeSection />
57
+ </Section>
58
+ <Section title={ __( 'Position', 'elementor' ) }>
59
+ <PositionSection />
60
+ </Section>
61
+ <Section title={ __( 'Typography', 'elementor' ) }>
62
+ <TypographySection />
63
+ </Section>
64
+ <Section title={ __( 'Background', 'elementor' ) }>
65
+ <BackgroundSection />
66
+ </Section>
67
+ <Section title={ __( 'Border', 'elementor' ) }>
68
+ <BorderSection />
69
+ </Section>
70
+ <Section title={ __( 'Effects', 'elementor' ) }>
71
+ <EffectsSection />
72
+ </Section>
73
+ </SectionsList>
74
+ </StyleInheritanceProvider>
74
75
  </SessionStorageProvider>
75
76
  </StyleProvider>
76
77
  </ClassesPropProvider>
@@ -89,7 +90,7 @@ function useFirstElementStyleDef( currentClassesProp: PropKey ) {
89
90
  const { element } = useElement();
90
91
 
91
92
  const classesIds = useElementSetting< ClassesPropValue >( element.id, currentClassesProp )?.value || [];
92
- const stylesDefs = useElementStyles( element.id );
93
+ const stylesDefs = getElementStyles( element.id ) ?? {};
93
94
 
94
95
  return Object.values( stylesDefs ).find( ( styleDef ) => classesIds.includes( styleDef.id ) );
95
96
  }
@@ -0,0 +1,65 @@
1
+ import * as React from 'react';
2
+ import { createContext, type PropsWithChildren, useContext } from 'react';
3
+ import { useElementSetting } from '@elementor/editor-elements';
4
+ import { classesPropTypeUtil, type ClassesPropValue } from '@elementor/editor-props';
5
+ import { getBreakpointsTree } from '@elementor/editor-responsive';
6
+ import { stylesRepository } from '@elementor/editor-styles-repository';
7
+
8
+ import { createStylesInheritance } from '../styles-inheritance/create-styles-inheritance';
9
+ import { type SnapshotPropValue, type StylesInheritanceSnapshotGetter } from '../styles-inheritance/types';
10
+ import { useClassesProp } from './classes-prop-context';
11
+ import { useElement } from './element-context';
12
+ import { useStyle } from './style-context';
13
+
14
+ type ContextValue = {
15
+ getSnapshot: StylesInheritanceSnapshotGetter;
16
+ };
17
+
18
+ const Context = createContext< ContextValue | null >( null );
19
+
20
+ export function StyleInheritanceProvider( { children }: PropsWithChildren ) {
21
+ const styleDefs = useAppliedStyles();
22
+
23
+ const breakpointsTree = getBreakpointsTree();
24
+
25
+ const getSnapshot = createStylesInheritance( styleDefs, breakpointsTree );
26
+
27
+ return <Context.Provider value={ { getSnapshot } }>{ children }</Context.Provider>;
28
+ }
29
+
30
+ export function useStylesInheritanceFields< T extends readonly string[] >(
31
+ fields: T
32
+ ): { [ K in T[ number ] ]: SnapshotPropValue[] } | null {
33
+ const context = useContext( Context );
34
+ const { meta } = useStyle();
35
+
36
+ if ( ! context ) {
37
+ throw new Error( 'useStylesInheritanceFields must be used within a StyleInheritanceProvider' );
38
+ }
39
+
40
+ if ( ! meta ) {
41
+ return null;
42
+ }
43
+
44
+ const snapshot = context.getSnapshot( meta );
45
+
46
+ return fields.reduce(
47
+ ( acc, key: T[ number ] ) => ( { ...acc, [ key ]: snapshot?.[ key ] ?? [] } ),
48
+ {} as { [ K in T[ number ] ]: SnapshotPropValue[] }
49
+ );
50
+ }
51
+
52
+ export function useStylesInheritanceField( field: string ): SnapshotPropValue[] {
53
+ return useStylesInheritanceFields( [ field ] )?.[ field ] ?? [];
54
+ }
55
+
56
+ const useAppliedStyles = () => {
57
+ const { element } = useElement();
58
+ const currentClassesProp = useClassesProp();
59
+ const classesProp = useElementSetting< ClassesPropValue >( element.id, currentClassesProp );
60
+
61
+ const appliedStyles = classesPropTypeUtil.extract( classesProp );
62
+ const allStyles = stylesRepository.all();
63
+
64
+ return allStyles.filter( ( style ) => appliedStyles?.includes( style.id ) );
65
+ };
@@ -1,6 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import type { ComponentProps } from 'react';
3
3
 
4
+ import { useElement } from '../contexts/element-context';
4
5
  import { ControlTypeNotFoundError } from '../errors';
5
6
  import { type ControlType, type ControlTypes, getControlByType } from './controls-registry';
6
7
 
@@ -24,6 +25,7 @@ type ControlProps< T extends ControlType > = AnyPropertyRequired< ComponentProps
24
25
 
25
26
  export const Control = < T extends ControlType >( { props, type }: ControlProps< T > ) => {
26
27
  const ControlByType = getControlByType( type );
28
+ const { element } = useElement();
27
29
 
28
30
  if ( ! ControlByType ) {
29
31
  throw new ControlTypeNotFoundError( {
@@ -32,5 +34,5 @@ export const Control = < T extends ControlType >( { props, type }: ControlProps<
32
34
  }
33
35
 
34
36
  // @ts-expect-error ControlComponent props are inferred from the type (T).
35
- return <ControlByType { ...props } />;
37
+ return <ControlByType { ...props } context={ { elementId: element.id } } />;
36
38
  };
@@ -34,6 +34,11 @@ type DynamicSelectionProps = {
34
34
  onSelect?: () => void;
35
35
  };
36
36
 
37
+ type NoResultsProps = {
38
+ searchValue: string;
39
+ onClear?: () => void;
40
+ };
41
+
37
42
  export const DynamicSelection = ( { onSelect }: DynamicSelectionProps ) => {
38
43
  const [ searchValue, setSearchValue ] = useState( '' );
39
44
  const { groups: dynamicGroups } = getAtomicDynamicTags() || {};
@@ -47,6 +52,8 @@ export const DynamicSelection = ( { onSelect }: DynamicSelectionProps ) => {
47
52
 
48
53
  const options = useFilteredOptions( searchValue );
49
54
 
55
+ const hasNoDynamicTags = ! options.length && ! searchValue.trim();
56
+
50
57
  const handleSearch = ( event: React.ChangeEvent< HTMLInputElement > ) => {
51
58
  setSearchValue( event.target.value );
52
59
  };
@@ -63,85 +70,115 @@ export const DynamicSelection = ( { onSelect }: DynamicSelectionProps ) => {
63
70
 
64
71
  return (
65
72
  <Stack>
66
- <Box px={ 1.5 } pb={ 1 }>
67
- <TextField
68
- fullWidth
69
- size={ SIZE }
70
- value={ searchValue }
71
- onChange={ handleSearch }
72
- placeholder={ __( 'Search dynamic tags…', 'elementor' ) }
73
- InputProps={ {
74
- startAdornment: (
75
- <InputAdornment position="start">
76
- <SearchIcon fontSize={ SIZE } />
77
- </InputAdornment>
78
- ),
79
- } }
80
- />
81
- </Box>
82
- <Divider />
83
- <Box sx={ { overflowY: 'auto', height: 260, width: 220 } }>
84
- { options.length > 0 ? (
85
- <MenuList role="listbox" tabIndex={ 0 }>
86
- { options.map( ( [ category, items ], index ) => (
87
- <Fragment key={ index }>
88
- <ListSubheader sx={ { px: 1.5, typography: 'caption', color: 'text.tertiary' } }>
89
- { dynamicGroups?.[ category ]?.title || category }
90
- </ListSubheader>
91
- { items.map( ( { value, label: tagLabel } ) => {
92
- const isSelected = isCurrentValueDynamic && value === dynamicValue?.name;
93
-
94
- return (
95
- <MenuItem
96
- key={ value }
97
- selected={ isSelected }
98
- // eslint-disable-next-line jsx-a11y/no-autofocus
99
- autoFocus={ isSelected }
100
- sx={ { px: 1.5, typography: 'caption' } }
101
- onClick={ () => handleSetDynamicTag( value ) }
73
+ { hasNoDynamicTags ? (
74
+ <NoDynamicTags />
75
+ ) : (
76
+ <Fragment>
77
+ <Box px={ 1.5 } pb={ 1 }>
78
+ <TextField
79
+ fullWidth
80
+ size={ SIZE }
81
+ value={ searchValue }
82
+ onChange={ handleSearch }
83
+ placeholder={ __( 'Search dynamic tags…', 'elementor' ) }
84
+ InputProps={ {
85
+ startAdornment: (
86
+ <InputAdornment position="start">
87
+ <SearchIcon fontSize={ SIZE } />
88
+ </InputAdornment>
89
+ ),
90
+ } }
91
+ />
92
+ </Box>
93
+ <Divider />
94
+ <Box sx={ { overflowY: 'auto', height: 260, width: 220 } }>
95
+ { options.length > 0 ? (
96
+ <MenuList role="listbox" tabIndex={ 0 }>
97
+ { options.map( ( [ category, items ], index ) => (
98
+ <Fragment key={ index }>
99
+ <ListSubheader
100
+ sx={ { px: 1.5, typography: 'caption', color: 'text.tertiary' } }
102
101
  >
103
- { tagLabel }
104
- </MenuItem>
105
- );
106
- } ) }
107
- </Fragment>
108
- ) ) }
109
- </MenuList>
110
- ) : (
111
- <Stack
112
- gap={ 1 }
113
- alignItems="center"
114
- justifyContent="center"
115
- height="100%"
116
- p={ 2.5 }
117
- color="text.secondary"
118
- sx={ { pb: 3.5 } }
119
- >
120
- <DatabaseIcon fontSize="large" />
121
- <Typography align="center" variant="subtitle2">
122
- { __( 'Sorry, nothing matched', 'elementor' ) }
123
- <br />
124
- &ldquo;{ searchValue }&rdquo;.
125
- </Typography>
126
- <Typography align="center" variant="caption">
127
- { __( 'Try something else.', 'elementor' ) }
128
- &nbsp;
129
- <Link
130
- color="text.secondary"
131
- variant="caption"
132
- component="button"
133
- onClick={ () => setSearchValue( '' ) }
134
- >
135
- { __( 'Clear & try again', 'elementor' ) }
136
- </Link>
137
- </Typography>
138
- </Stack>
139
- ) }
140
- </Box>
102
+ { dynamicGroups?.[ category ]?.title || category }
103
+ </ListSubheader>
104
+ { items.map( ( { value, label: tagLabel } ) => {
105
+ const isSelected = isCurrentValueDynamic && value === dynamicValue?.name;
106
+
107
+ return (
108
+ <MenuItem
109
+ key={ value }
110
+ selected={ isSelected }
111
+ // eslint-disable-next-line jsx-a11y/no-autofocus
112
+ autoFocus={ isSelected }
113
+ sx={ { px: 1.5, typography: 'caption' } }
114
+ onClick={ () => handleSetDynamicTag( value ) }
115
+ >
116
+ { tagLabel }
117
+ </MenuItem>
118
+ );
119
+ } ) }
120
+ </Fragment>
121
+ ) ) }
122
+ </MenuList>
123
+ ) : (
124
+ <NoResults searchValue={ searchValue } onClear={ () => setSearchValue( '' ) } />
125
+ ) }
126
+ </Box>
127
+ </Fragment>
128
+ ) }
141
129
  </Stack>
142
130
  );
143
131
  };
144
132
 
133
+ const NoResults = ( { searchValue, onClear }: NoResultsProps ) => (
134
+ <Stack
135
+ gap={ 1 }
136
+ alignItems="center"
137
+ justifyContent="center"
138
+ height="100%"
139
+ p={ 2.5 }
140
+ color="text.secondary"
141
+ sx={ { pb: 3.5 } }
142
+ >
143
+ <DatabaseIcon fontSize="large" />
144
+ <Typography align="center" variant="subtitle2">
145
+ { __( 'Sorry, nothing matched', 'elementor' ) }
146
+ <br />
147
+ &ldquo;{ searchValue }&rdquo;.
148
+ </Typography>
149
+ <Typography align="center" variant="caption">
150
+ { __( 'Try something else.', 'elementor' ) }
151
+ &nbsp;
152
+ <Link color="text.secondary" variant="caption" component="button" onClick={ onClear }>
153
+ { __( 'Clear & try again', 'elementor' ) }
154
+ </Link>
155
+ </Typography>
156
+ </Stack>
157
+ );
158
+
159
+ const NoDynamicTags = () => (
160
+ <Box sx={ { overflowY: 'hidden', height: 297, width: 220 } }>
161
+ <Divider />
162
+ <Stack
163
+ gap={ 1 }
164
+ alignItems="center"
165
+ justifyContent="center"
166
+ height="100%"
167
+ p={ 2.5 }
168
+ color="text.secondary"
169
+ sx={ { pb: 3.5 } }
170
+ >
171
+ <DatabaseIcon fontSize="large" />
172
+ <Typography align="center" variant="subtitle2">
173
+ { __( 'Streamline your workflow with dynamic tags', 'elementor' ) }
174
+ </Typography>
175
+ <Typography align="center" variant="caption">
176
+ { __( 'You’ll need Elementor Pro to use this feature.', 'elementor' ) }
177
+ </Typography>
178
+ </Stack>
179
+ </Box>
180
+ );
181
+
145
182
  const useFilteredOptions = ( searchValue: string ): OptionEntry[] => {
146
183
  const dynamicTags = usePropDynamicTags();
147
184
 
package/src/init.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { injectIntoLogic } from '@elementor/editor';
2
+ import { PrefetchUserData } from '@elementor/editor-current-user';
2
3
  import { __registerPanel as registerPanel } from '@elementor/editor-panels';
3
4
  import { blockCommand } from '@elementor/editor-v1-adapters';
4
5
 
@@ -16,6 +17,11 @@ export default function init() {
16
17
  component: EditingPanelHooks,
17
18
  } );
18
19
 
20
+ injectIntoLogic( {
21
+ id: 'current-user-data',
22
+ component: PrefetchUserData,
23
+ } );
24
+
19
25
  // TODO: Move it from here once we have dynamic package.
20
26
  initDynamics();
21
27
  }
package/src/sync/types.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { type ControlItem, type V1Element } from '@elementor/editor-elements';
2
2
  import { type PropsSchema } from '@elementor/editor-props';
3
3
 
4
- type SupportedFonts = 'system' | 'googlefonts' | 'customfonts';
4
+ export type SupportedFonts = 'system' | 'googlefonts' | 'custom';
5
5
 
6
6
  type EnqueueFont = ( fontFamily: string, context?: 'preview' | 'editor' ) => void;
7
7
 
@@ -1,23 +0,0 @@
1
- import { useEffect } from 'react';
2
- import { getSelectedElements, isElementInContainer, type V1Element } from '@elementor/editor-elements';
3
- import { __privateListenTo as listenTo, type CommandEvent, commandStartEvent } from '@elementor/editor-v1-adapters';
4
-
5
- import { usePanelActions } from '../panel';
6
- import { isAtomicWidgetSelected } from '../sync/is-atomic-widget-selected';
7
-
8
- export const useCloseEditorPanel = () => {
9
- const { close } = usePanelActions();
10
-
11
- return useEffect( () => {
12
- return listenTo( commandStartEvent( 'document/elements/delete' ), ( e ) => {
13
- const selectedElement = getSelectedElements()[ 0 ];
14
- const { container: deletedContainer } = ( e as CommandEvent< { container: V1Element } > )?.args;
15
- const isSelectedElementInDeletedContainer =
16
- deletedContainer && selectedElement && isElementInContainer( selectedElement, deletedContainer );
17
-
18
- if ( isSelectedElementInDeletedContainer && isAtomicWidgetSelected() ) {
19
- close();
20
- }
21
- } );
22
- }, [] ); // eslint-disable-line react-hooks/exhaustive-deps
23
- };