@elementor/editor-variables 0.18.0 → 3.32.0-21

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 (56) hide show
  1. package/CHANGELOG.md +0 -28
  2. package/dist/index.d.mts +19 -1
  3. package/dist/index.d.ts +19 -1
  4. package/dist/index.js +1282 -1026
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +1262 -990
  7. package/dist/index.mjs.map +1 -1
  8. package/package.json +16 -14
  9. package/src/api.ts +18 -2
  10. package/src/components/fields/color-field.tsx +3 -3
  11. package/src/components/fields/font-field.tsx +21 -10
  12. package/src/components/fields/label-field.tsx +31 -5
  13. package/src/components/ui/edit-confirmation-dialog.tsx +75 -0
  14. package/src/components/ui/missing-variable-alert.tsx +39 -0
  15. package/src/components/ui/no-variables.tsx +59 -26
  16. package/src/components/ui/tags/missing-tag.tsx +25 -0
  17. package/src/components/ui/variable/assigned-variable.tsx +11 -14
  18. package/src/components/ui/variable/deleted-variable.tsx +102 -50
  19. package/src/components/ui/variable/missing-variable.tsx +44 -0
  20. package/src/components/{color-variable-creation.tsx → variable-creation.tsx} +51 -22
  21. package/src/components/variable-edit.tsx +221 -0
  22. package/src/components/variable-restore.tsx +117 -0
  23. package/src/components/variable-selection-popover.tsx +91 -92
  24. package/src/components/variables-manager/variables-manager-panel.tsx +115 -0
  25. package/src/components/{font-variables-selection.tsx → variables-selection.tsx} +38 -17
  26. package/src/context/variable-selection-popover.context.tsx +19 -0
  27. package/src/context/variable-type-context.tsx +23 -0
  28. package/src/controls/variable-control.tsx +26 -0
  29. package/src/hooks/use-initial-value.ts +22 -0
  30. package/src/hooks/use-permissions.ts +15 -0
  31. package/src/hooks/use-prop-variable-action.tsx +53 -0
  32. package/src/hooks/use-prop-variables.ts +2 -2
  33. package/src/index.ts +1 -0
  34. package/src/init.ts +33 -4
  35. package/src/register-variable-types.tsx +29 -0
  36. package/src/repeater-injections.ts +5 -1
  37. package/src/service.ts +2 -19
  38. package/src/transformers/inheritance-transformer.tsx +30 -0
  39. package/src/transformers/utils/resolve-css-variable.ts +24 -0
  40. package/src/transformers/variable-transformer.ts +3 -16
  41. package/src/utils/tracking.ts +39 -0
  42. package/src/utils/validations.ts +40 -6
  43. package/src/variables-registry/create-variable-type-registry.ts +77 -0
  44. package/src/variables-registry/variable-type-registry.ts +3 -0
  45. package/src/components/color-variable-edit.tsx +0 -157
  46. package/src/components/color-variables-selection.tsx +0 -128
  47. package/src/components/font-variable-creation.tsx +0 -106
  48. package/src/components/font-variable-edit.tsx +0 -157
  49. package/src/components/variable-selection-popover.context.ts +0 -7
  50. package/src/controls/color-variable-control.tsx +0 -39
  51. package/src/controls/font-variable-control.tsx +0 -37
  52. package/src/hooks/use-prop-color-variable-action.tsx +0 -25
  53. package/src/hooks/use-prop-font-variable-action.tsx +0 -25
  54. package/src/init-color-variables.ts +0 -27
  55. package/src/init-font-variables.ts +0 -24
  56. package/src/utils.ts +0 -20
@@ -1,76 +1,128 @@
1
1
  import * as React from 'react';
2
- import { useState } from 'react';
2
+ import { useId, useRef, useState } from 'react';
3
3
  import { useBoundProp } from '@elementor/editor-controls';
4
- import { type PropTypeUtil } from '@elementor/editor-props';
5
- import { isExperimentActive } from '@elementor/editor-v1-adapters';
6
- import { Backdrop, Infotip } from '@elementor/ui';
4
+ import { type PropTypeKey } from '@elementor/editor-props';
5
+ import { Backdrop, bindPopover, Box, Infotip, Popover, usePopupState } from '@elementor/ui';
7
6
 
7
+ import { VariableTypeProvider } from '../../../context/variable-type-context';
8
+ import { usePermissions } from '../../../hooks/use-permissions';
8
9
  import { restoreVariable } from '../../../hooks/use-prop-variables';
9
10
  import { type Variable } from '../../../types';
11
+ import { getVariableType } from '../../../variables-registry/variable-type-registry';
12
+ import { VariableRestore } from '../../variable-restore';
10
13
  import { DeletedVariableAlert } from '../deleted-variable-alert';
11
14
  import { DeletedTag } from '../tags/deleted-tag';
12
15
 
13
- const isV331Active = isExperimentActive( 'e_v_3_31' );
14
-
15
16
  type Props = {
16
17
  variable: Variable;
17
- variablePropTypeUtil: PropTypeUtil< string, string >;
18
- fallbackPropTypeUtil: PropTypeUtil< string, string | null > | PropTypeUtil< string, string >;
18
+ propTypeKey: PropTypeKey;
19
+ };
20
+
21
+ type Handlers = {
22
+ onUnlink?: () => void;
23
+ onRestore?: () => void;
19
24
  };
20
25
 
21
- export const DeletedVariable = ( { variable, variablePropTypeUtil, fallbackPropTypeUtil }: Props ) => {
26
+ export const DeletedVariable = ( { variable, propTypeKey }: Props ) => {
27
+ const { fallbackPropTypeUtil, propTypeUtil } = getVariableType( propTypeKey );
28
+
22
29
  const { setValue } = useBoundProp();
23
- const [ showInfotip, setShowInfotip ] = useState< boolean >( false );
24
30
 
25
- const toggleInfotip = () => setShowInfotip( ( prev ) => ! prev );
31
+ const userPermissions = usePermissions();
26
32
 
33
+ const [ showInfotip, setShowInfotip ] = useState< boolean >( false );
34
+ const toggleInfotip = () => setShowInfotip( ( prev ) => ! prev );
27
35
  const closeInfotip = () => setShowInfotip( false );
28
36
 
29
- const unlinkVariable = () => {
30
- setValue( fallbackPropTypeUtil.create( variable.value ) );
31
- };
37
+ const deletedChipAnchorRef = useRef< HTMLDivElement >( null );
38
+
39
+ const popupId = useId();
40
+ const popupState = usePopupState( {
41
+ variant: 'popover',
42
+ popupId: `elementor-variables-restore-${ popupId }`,
43
+ } );
44
+
45
+ const handlers: Handlers = {};
32
46
 
33
- const handleRestore = () => {
34
- if ( ! variable.key ) {
35
- return;
36
- }
47
+ if ( userPermissions.canUnlink() ) {
48
+ handlers.onUnlink = () => {
49
+ setValue( fallbackPropTypeUtil.create( variable.value ) );
50
+ };
51
+ }
37
52
 
38
- restoreVariable( variable.key ).then( ( key ) => {
39
- setValue( variablePropTypeUtil.create( key ) );
40
- closeInfotip();
41
- } );
53
+ if ( userPermissions.canRestore() ) {
54
+ handlers.onRestore = () => {
55
+ if ( ! variable.key ) {
56
+ return;
57
+ }
58
+
59
+ restoreVariable( variable.key )
60
+ .then( ( key ) => {
61
+ setValue( propTypeUtil.create( key ) );
62
+ closeInfotip();
63
+ } )
64
+ .catch( () => {
65
+ closeInfotip();
66
+ popupState.setAnchorEl( deletedChipAnchorRef.current );
67
+ popupState.open();
68
+ } );
69
+ };
70
+ }
71
+
72
+ const handleRestoreWithOverrides = () => {
73
+ popupState.close();
42
74
  };
43
75
 
44
76
  return (
45
77
  <>
46
- { showInfotip && <Backdrop open onClick={ closeInfotip } invisible /> }
47
- <Infotip
48
- color="warning"
49
- placement="right-start"
50
- open={ showInfotip }
51
- disableHoverListener
52
- onClose={ closeInfotip }
53
- content={
54
- <DeletedVariableAlert
55
- onClose={ closeInfotip }
56
- onUnlink={ unlinkVariable }
57
- onRestore={ isV331Active ? handleRestore : undefined }
58
- label={ variable.label }
59
- />
60
- }
61
- slotProps={ {
62
- popper: {
63
- modifiers: [
64
- {
65
- name: 'offset',
66
- options: { offset: [ 0, 24 ] },
67
- },
68
- ],
69
- },
70
- } }
71
- >
72
- <DeletedTag label={ variable.label } onClick={ toggleInfotip } />
73
- </Infotip>
78
+ <Box ref={ deletedChipAnchorRef }>
79
+ { showInfotip && <Backdrop open onClick={ closeInfotip } invisible /> }
80
+ <Infotip
81
+ color="warning"
82
+ placement="right-start"
83
+ open={ showInfotip }
84
+ disableHoverListener
85
+ onClose={ closeInfotip }
86
+ content={
87
+ <DeletedVariableAlert
88
+ onClose={ closeInfotip }
89
+ onUnlink={ handlers.onUnlink }
90
+ onRestore={ handlers.onRestore }
91
+ label={ variable.label }
92
+ />
93
+ }
94
+ slotProps={ {
95
+ popper: {
96
+ modifiers: [
97
+ {
98
+ name: 'offset',
99
+ options: { offset: [ 0, 24 ] },
100
+ },
101
+ ],
102
+ },
103
+ } }
104
+ >
105
+ <DeletedTag label={ variable.label } onClick={ toggleInfotip } />
106
+ </Infotip>
107
+
108
+ <Popover
109
+ disableScrollLock
110
+ anchorOrigin={ { vertical: 'bottom', horizontal: 'right' } }
111
+ transformOrigin={ { vertical: 'top', horizontal: 'right' } }
112
+ PaperProps={ {
113
+ sx: { my: 1 },
114
+ } }
115
+ { ...bindPopover( popupState ) }
116
+ >
117
+ <VariableTypeProvider propTypeKey={ propTypeKey }>
118
+ <VariableRestore
119
+ variableId={ variable.key ?? '' }
120
+ onClose={ popupState.close }
121
+ onSubmit={ handleRestoreWithOverrides }
122
+ />
123
+ </VariableTypeProvider>
124
+ </Popover>
125
+ </Box>
74
126
  </>
75
127
  );
76
128
  };
@@ -0,0 +1,44 @@
1
+ import * as React from 'react';
2
+ import { useState } from 'react';
3
+ import { useBoundProp } from '@elementor/editor-controls';
4
+ import { Backdrop, Infotip } from '@elementor/ui';
5
+ import { __ } from '@wordpress/i18n';
6
+
7
+ import { MissingVariableAlert } from '../missing-variable-alert';
8
+ import { MissingTag } from '../tags/missing-tag';
9
+
10
+ export const MissingVariable = () => {
11
+ const { setValue } = useBoundProp();
12
+
13
+ const [ infotipVisible, setInfotipVisible ] = useState< boolean >( false );
14
+ const toggleInfotip = () => setInfotipVisible( ( prev ) => ! prev );
15
+ const closeInfotip = () => setInfotipVisible( false );
16
+
17
+ const clearValue = () => setValue( null );
18
+
19
+ return (
20
+ <>
21
+ { infotipVisible && <Backdrop open onClick={ closeInfotip } invisible /> }
22
+ <Infotip
23
+ color="warning"
24
+ placement="right-start"
25
+ open={ infotipVisible }
26
+ disableHoverListener
27
+ onClose={ closeInfotip }
28
+ content={ <MissingVariableAlert onClose={ closeInfotip } onClear={ clearValue } /> }
29
+ slotProps={ {
30
+ popper: {
31
+ modifiers: [
32
+ {
33
+ name: 'offset',
34
+ options: { offset: [ 0, 24 ] },
35
+ },
36
+ ],
37
+ },
38
+ } }
39
+ >
40
+ <MissingTag label={ __( 'Missing variable', 'elementor' ) } onClick={ toggleInfotip } />
41
+ </Infotip>
42
+ </>
43
+ );
44
+ };
@@ -3,14 +3,16 @@ import { useState } from 'react';
3
3
  import { PopoverContent, useBoundProp } from '@elementor/editor-controls';
4
4
  import { PopoverBody } from '@elementor/editor-editing-panel';
5
5
  import { PopoverHeader } from '@elementor/editor-ui';
6
- import { ArrowLeftIcon, BrushIcon } from '@elementor/icons';
6
+ import { ArrowLeftIcon } from '@elementor/icons';
7
7
  import { Button, CardActions, Divider, FormHelperText, IconButton } from '@elementor/ui';
8
8
  import { __ } from '@wordpress/i18n';
9
9
 
10
+ import { useVariableType } from '../context/variable-type-context';
11
+ import { useInitialValue } from '../hooks/use-initial-value';
10
12
  import { createVariable } from '../hooks/use-prop-variables';
11
- import { colorVariablePropTypeUtil } from '../prop-types/color-variable-prop-type';
12
- import { ColorField } from './fields/color-field';
13
- import { LabelField } from './fields/label-field';
13
+ import { trackVariableEvent } from '../utils/tracking';
14
+ import { ERROR_MESSAGES, mapServerError } from '../utils/validations';
15
+ import { LabelField, useLabelError } from './fields/label-field';
14
16
 
15
17
  const SIZE = 'tiny';
16
18
 
@@ -19,15 +21,21 @@ type Props = {
19
21
  onClose: () => void;
20
22
  };
21
23
 
22
- export const ColorVariableCreation = ( { onGoBack, onClose }: Props ) => {
23
- const { setValue: setVariable } = useBoundProp( colorVariablePropTypeUtil );
24
+ export const VariableCreation = ( { onGoBack, onClose }: Props ) => {
25
+ const { icon: VariableIcon, valueField: ValueField, variableType, propTypeUtil } = useVariableType();
24
26
 
25
- const [ color, setColor ] = useState( '' );
27
+ const { setValue: setVariable, path } = useBoundProp( propTypeUtil );
28
+
29
+ const initialValue = useInitialValue();
30
+
31
+ const [ value, setValue ] = useState( initialValue );
26
32
  const [ label, setLabel ] = useState( '' );
27
33
  const [ errorMessage, setErrorMessage ] = useState( '' );
28
34
 
35
+ const { labelFieldError, setLabelFieldError } = useLabelError();
36
+
29
37
  const resetFields = () => {
30
- setColor( '' );
38
+ setValue( '' );
31
39
  setLabel( '' );
32
40
  setErrorMessage( '' );
33
41
  };
@@ -37,26 +45,46 @@ export const ColorVariableCreation = ( { onGoBack, onClose }: Props ) => {
37
45
  onClose();
38
46
  };
39
47
 
40
- const handleCreate = () => {
48
+ const handleCreateAndTrack = () => {
41
49
  createVariable( {
42
- value: color,
50
+ value,
43
51
  label,
44
- type: colorVariablePropTypeUtil.key,
52
+ type: propTypeUtil.key,
45
53
  } )
46
54
  .then( ( key ) => {
47
55
  setVariable( key );
48
56
  closePopover();
49
57
  } )
50
58
  .catch( ( error ) => {
51
- setErrorMessage( error.message );
59
+ const mappedError = mapServerError( error );
60
+ if ( mappedError && 'label' === mappedError.field ) {
61
+ setLabel( '' );
62
+ setLabelFieldError( {
63
+ value: label,
64
+ message: mappedError.message,
65
+ } );
66
+ return;
67
+ }
68
+
69
+ setErrorMessage( ERROR_MESSAGES.UNEXPECTED_ERROR );
52
70
  } );
71
+
72
+ trackVariableEvent( {
73
+ varType: variableType,
74
+ controlPath: path.join( '.' ),
75
+ action: 'save',
76
+ } );
53
77
  };
54
78
 
55
79
  const hasEmptyValue = () => {
56
- return '' === color.trim() || '' === label.trim();
80
+ return '' === value.trim() || '' === label.trim();
81
+ };
82
+
83
+ const hasErrors = () => {
84
+ return !! errorMessage;
57
85
  };
58
86
 
59
- const isSubmitDisabled = hasEmptyValue();
87
+ const isSubmitDisabled = hasEmptyValue() || hasErrors();
60
88
 
61
89
  return (
62
90
  <PopoverBody height="auto">
@@ -68,7 +96,7 @@ export const ColorVariableCreation = ( { onGoBack, onClose }: Props ) => {
68
96
  <ArrowLeftIcon fontSize={ SIZE } />
69
97
  </IconButton>
70
98
  ) }
71
- <BrushIcon fontSize={ SIZE } />
99
+ <VariableIcon fontSize={ SIZE } />
72
100
  </>
73
101
  }
74
102
  title={ __( 'Create variable', 'elementor' ) }
@@ -80,15 +108,16 @@ export const ColorVariableCreation = ( { onGoBack, onClose }: Props ) => {
80
108
  <PopoverContent p={ 2 }>
81
109
  <LabelField
82
110
  value={ label }
83
- onChange={ ( value ) => {
84
- setLabel( value );
111
+ error={ labelFieldError }
112
+ onChange={ ( newValue ) => {
113
+ setLabel( newValue );
85
114
  setErrorMessage( '' );
86
115
  } }
87
116
  />
88
- <ColorField
89
- value={ color }
90
- onChange={ ( value ) => {
91
- setColor( value );
117
+ <ValueField
118
+ value={ value }
119
+ onChange={ ( newValue ) => {
120
+ setValue( newValue );
92
121
  setErrorMessage( '' );
93
122
  } }
94
123
  />
@@ -97,7 +126,7 @@ export const ColorVariableCreation = ( { onGoBack, onClose }: Props ) => {
97
126
  </PopoverContent>
98
127
 
99
128
  <CardActions sx={ { pt: 0.5, pb: 1 } }>
100
- <Button size="small" variant="contained" disabled={ isSubmitDisabled } onClick={ handleCreate }>
129
+ <Button size="small" variant="contained" disabled={ isSubmitDisabled } onClick={ handleCreateAndTrack }>
101
130
  { __( 'Create', 'elementor' ) }
102
131
  </Button>
103
132
  </CardActions>
@@ -0,0 +1,221 @@
1
+ import * as React from 'react';
2
+ import { useEffect, useState } from 'react';
3
+ import { PopoverContent, useBoundProp } from '@elementor/editor-controls';
4
+ import { useSuppressedMessage } from '@elementor/editor-current-user';
5
+ import { PopoverBody } from '@elementor/editor-editing-panel';
6
+ import { PopoverHeader } from '@elementor/editor-ui';
7
+ import { ArrowLeftIcon, TrashIcon } from '@elementor/icons';
8
+ import { Button, CardActions, Divider, FormHelperText, IconButton } from '@elementor/ui';
9
+ import { __ } from '@wordpress/i18n';
10
+
11
+ import { useVariableType } from '../context/variable-type-context';
12
+ import { usePermissions } from '../hooks/use-permissions';
13
+ import { deleteVariable, updateVariable, useVariable } from '../hooks/use-prop-variables';
14
+ import { styleVariablesRepository } from '../style-variables-repository';
15
+ import { ERROR_MESSAGES, mapServerError } from '../utils/validations';
16
+ import { LabelField, useLabelError } from './fields/label-field';
17
+ import { DeleteConfirmationDialog } from './ui/delete-confirmation-dialog';
18
+ import { EDIT_CONFIRMATION_DIALOG_ID, EditConfirmationDialog } from './ui/edit-confirmation-dialog';
19
+
20
+ const SIZE = 'tiny';
21
+
22
+ type Props = {
23
+ editId: string;
24
+ onClose: () => void;
25
+ onGoBack?: () => void;
26
+ onSubmit?: () => void;
27
+ };
28
+
29
+ export const VariableEdit = ( { onClose, onGoBack, onSubmit, editId }: Props ) => {
30
+ const { icon: VariableIcon, valueField: ValueField, variableType, propTypeUtil } = useVariableType();
31
+
32
+ const { setValue: notifyBoundPropChange, value: assignedValue } = useBoundProp( propTypeUtil );
33
+ const [ isMessageSuppressed, suppressMessage ] = useSuppressedMessage( EDIT_CONFIRMATION_DIALOG_ID );
34
+ const [ deleteConfirmation, setDeleteConfirmation ] = useState( false );
35
+ const [ editConfirmation, setEditConfirmation ] = useState( false );
36
+ const [ errorMessage, setErrorMessage ] = useState( '' );
37
+
38
+ const { labelFieldError, setLabelFieldError } = useLabelError();
39
+ const variable = useVariable( editId );
40
+
41
+ if ( ! variable ) {
42
+ throw new Error( `Global ${ variableType } variable not found` );
43
+ }
44
+
45
+ const userPermissions = usePermissions();
46
+
47
+ const [ value, setValue ] = useState( variable.value );
48
+ const [ label, setLabel ] = useState( variable.label );
49
+
50
+ useEffect( () => {
51
+ styleVariablesRepository.update( {
52
+ [ editId ]: {
53
+ ...variable,
54
+ value,
55
+ },
56
+ } );
57
+
58
+ return () => {
59
+ styleVariablesRepository.update( {
60
+ [ editId ]: { ...variable },
61
+ } );
62
+ };
63
+ }, [ editId, value, variable ] );
64
+
65
+ const handleUpdate = () => {
66
+ if ( isMessageSuppressed ) {
67
+ handleSaveVariable();
68
+ } else {
69
+ setEditConfirmation( true );
70
+ }
71
+ };
72
+
73
+ const handleSaveVariable = () => {
74
+ updateVariable( editId, {
75
+ value,
76
+ label,
77
+ } )
78
+ .then( () => {
79
+ maybeTriggerBoundPropChange();
80
+ onSubmit?.();
81
+ } )
82
+ .catch( ( error ) => {
83
+ const mappedError = mapServerError( error );
84
+ if ( mappedError && 'label' === mappedError.field ) {
85
+ setLabel( '' );
86
+ setLabelFieldError( {
87
+ value: label,
88
+ message: mappedError.message,
89
+ } );
90
+ return;
91
+ }
92
+
93
+ setErrorMessage( ERROR_MESSAGES.UNEXPECTED_ERROR );
94
+ } );
95
+ };
96
+
97
+ const handleDelete = () => {
98
+ deleteVariable( editId ).then( () => {
99
+ maybeTriggerBoundPropChange();
100
+ onSubmit?.();
101
+ } );
102
+ };
103
+
104
+ const maybeTriggerBoundPropChange = () => {
105
+ if ( editId === assignedValue ) {
106
+ notifyBoundPropChange( editId );
107
+ }
108
+ };
109
+
110
+ const handleDeleteConfirmation = () => {
111
+ setDeleteConfirmation( true );
112
+ };
113
+
114
+ const closeDeleteDialog = () => () => {
115
+ setDeleteConfirmation( false );
116
+ };
117
+
118
+ const closeEditDialog = () => () => {
119
+ setEditConfirmation( false );
120
+ };
121
+
122
+ const actions = [];
123
+
124
+ if ( userPermissions.canDelete() ) {
125
+ actions.push(
126
+ <IconButton
127
+ key="delete"
128
+ size={ SIZE }
129
+ aria-label={ __( 'Delete', 'elementor' ) }
130
+ onClick={ handleDeleteConfirmation }
131
+ >
132
+ <TrashIcon fontSize={ SIZE } />
133
+ </IconButton>
134
+ );
135
+ }
136
+
137
+ const hasEmptyValues = () => {
138
+ return ! value.trim() || ! label.trim();
139
+ };
140
+
141
+ const noValueChanged = () => {
142
+ return value === variable.value && label === variable.label;
143
+ };
144
+
145
+ const hasErrors = () => {
146
+ return !! errorMessage;
147
+ };
148
+
149
+ const isSubmitDisabled = noValueChanged() || hasEmptyValues() || hasErrors();
150
+
151
+ return (
152
+ <>
153
+ <PopoverBody height="auto">
154
+ <PopoverHeader
155
+ title={ __( 'Edit variable', 'elementor' ) }
156
+ onClose={ onClose }
157
+ icon={
158
+ <>
159
+ { onGoBack && (
160
+ <IconButton
161
+ size={ SIZE }
162
+ aria-label={ __( 'Go Back', 'elementor' ) }
163
+ onClick={ onGoBack }
164
+ >
165
+ <ArrowLeftIcon fontSize={ SIZE } />
166
+ </IconButton>
167
+ ) }
168
+ <VariableIcon fontSize={ SIZE } />
169
+ </>
170
+ }
171
+ actions={ actions }
172
+ />
173
+
174
+ <Divider />
175
+
176
+ <PopoverContent p={ 2 }>
177
+ <LabelField
178
+ value={ label }
179
+ error={ labelFieldError }
180
+ onChange={ ( newValue ) => {
181
+ setLabel( newValue );
182
+ setErrorMessage( '' );
183
+ } }
184
+ />
185
+ <ValueField
186
+ value={ value }
187
+ onChange={ ( newValue ) => {
188
+ setValue( newValue );
189
+ setErrorMessage( '' );
190
+ } }
191
+ />
192
+
193
+ { errorMessage && <FormHelperText error>{ errorMessage }</FormHelperText> }
194
+ </PopoverContent>
195
+
196
+ <CardActions sx={ { pt: 0.5, pb: 1 } }>
197
+ <Button size="small" variant="contained" disabled={ isSubmitDisabled } onClick={ handleUpdate }>
198
+ { __( 'Save', 'elementor' ) }
199
+ </Button>
200
+ </CardActions>
201
+ </PopoverBody>
202
+
203
+ { deleteConfirmation && (
204
+ <DeleteConfirmationDialog
205
+ open
206
+ label={ label }
207
+ onConfirm={ handleDelete }
208
+ closeDialog={ closeDeleteDialog() }
209
+ />
210
+ ) }
211
+
212
+ { editConfirmation && ! isMessageSuppressed && (
213
+ <EditConfirmationDialog
214
+ closeDialog={ closeEditDialog() }
215
+ onConfirm={ handleSaveVariable }
216
+ onSuppressMessage={ suppressMessage }
217
+ />
218
+ ) }
219
+ </>
220
+ );
221
+ };