@elementor/editor-variables 3.33.0-174 → 3.33.0-176
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +418 -289
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +391 -252
- package/dist/index.mjs.map +1 -1
- package/package.json +14 -14
- package/src/components/ui/menu-item-content.tsx +14 -11
- package/src/components/ui/tags/assigned-tag.tsx +6 -3
- package/src/components/variable-edit.tsx +7 -9
- package/src/components/variables-manager/hooks/use-error-navigation.ts +49 -0
- package/src/components/variables-manager/hooks/use-variables-manager-state.ts +16 -24
- package/src/components/variables-manager/variables-manager-panel.tsx +169 -102
- package/src/components/variables-selection.tsx +23 -7
- package/src/utils/validations.ts +54 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-variables",
|
|
3
|
-
"version": "3.33.0-
|
|
3
|
+
"version": "3.33.0-176",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "Elementor Team",
|
|
6
6
|
"homepage": "https://elementor.com/",
|
|
@@ -39,20 +39,20 @@
|
|
|
39
39
|
"dev": "tsup --config=../../tsup.dev.ts"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@elementor/editor": "3.33.0-
|
|
43
|
-
"@elementor/editor-canvas": "3.33.0-
|
|
44
|
-
"@elementor/editor-controls": "3.33.0-
|
|
45
|
-
"@elementor/editor-current-user": "3.33.0-
|
|
46
|
-
"@elementor/editor-editing-panel": "3.33.0-
|
|
47
|
-
"@elementor/editor-mcp": "3.33.0-
|
|
48
|
-
"@elementor/editor-panels": "3.33.0-
|
|
49
|
-
"@elementor/editor-props": "3.33.0-
|
|
50
|
-
"@elementor/editor-ui": "3.33.0-
|
|
51
|
-
"@elementor/editor-v1-adapters": "3.33.0-
|
|
52
|
-
"@elementor/http-client": "3.33.0-
|
|
42
|
+
"@elementor/editor": "3.33.0-176",
|
|
43
|
+
"@elementor/editor-canvas": "3.33.0-176",
|
|
44
|
+
"@elementor/editor-controls": "3.33.0-176",
|
|
45
|
+
"@elementor/editor-current-user": "3.33.0-176",
|
|
46
|
+
"@elementor/editor-editing-panel": "3.33.0-176",
|
|
47
|
+
"@elementor/editor-mcp": "3.33.0-176",
|
|
48
|
+
"@elementor/editor-panels": "3.33.0-176",
|
|
49
|
+
"@elementor/editor-props": "3.33.0-176",
|
|
50
|
+
"@elementor/editor-ui": "3.33.0-176",
|
|
51
|
+
"@elementor/editor-v1-adapters": "3.33.0-176",
|
|
52
|
+
"@elementor/http-client": "3.33.0-176",
|
|
53
53
|
"@elementor/icons": "1.53.0",
|
|
54
|
-
"@elementor/mixpanel": "3.33.0-
|
|
55
|
-
"@elementor/schema": "3.33.0-
|
|
54
|
+
"@elementor/mixpanel": "3.33.0-176",
|
|
55
|
+
"@elementor/schema": "3.33.0-176",
|
|
56
56
|
"@elementor/ui": "1.36.14",
|
|
57
57
|
"@wordpress/i18n": "^5.13.0"
|
|
58
58
|
},
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { EllipsisWithTooltip, type VirtualizedItem } from '@elementor/editor-ui';
|
|
3
3
|
import { EditIcon } from '@elementor/icons';
|
|
4
|
-
import { Box, IconButton, ListItemIcon, Typography } from '@elementor/ui';
|
|
4
|
+
import { Box, IconButton, ListItemIcon, Tooltip, Typography } from '@elementor/ui';
|
|
5
5
|
import { __ } from '@wordpress/i18n';
|
|
6
6
|
|
|
7
7
|
const SIZE = 'tiny';
|
|
8
|
+
const EDIT_LABEL = __( 'Edit variable', 'elementor' );
|
|
8
9
|
|
|
9
10
|
export const MenuItemContent = < T, V extends string >( { item }: { item: VirtualizedItem< T, V > } ) => {
|
|
10
11
|
const onEdit = item.onEdit as ( ( value: V ) => void ) | undefined;
|
|
@@ -41,16 +42,18 @@ export const MenuItemContent = < T, V extends string >( { item }: { item: Virtua
|
|
|
41
42
|
) }
|
|
42
43
|
</Box>
|
|
43
44
|
{ !! onEdit && (
|
|
44
|
-
<
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
e.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
45
|
+
<Tooltip placement="top" title={ EDIT_LABEL }>
|
|
46
|
+
<IconButton
|
|
47
|
+
sx={ { mx: 1, opacity: '0' } }
|
|
48
|
+
onClick={ ( e: React.MouseEvent< HTMLButtonElement > ) => {
|
|
49
|
+
e.stopPropagation();
|
|
50
|
+
onEdit( item.value );
|
|
51
|
+
} }
|
|
52
|
+
aria-label={ EDIT_LABEL }
|
|
53
|
+
>
|
|
54
|
+
<EditIcon color="action" fontSize={ SIZE } />
|
|
55
|
+
</IconButton>
|
|
56
|
+
</Tooltip>
|
|
54
57
|
) }
|
|
55
58
|
</>
|
|
56
59
|
);
|
|
@@ -4,6 +4,7 @@ import { Box, IconButton, Stack, Tooltip, Typography, UnstableTag as Tag, type U
|
|
|
4
4
|
import { __ } from '@wordpress/i18n';
|
|
5
5
|
|
|
6
6
|
export const SIZE = 'tiny';
|
|
7
|
+
const UNLINK_LABEL = __( 'Unlink variable', 'elementor' );
|
|
7
8
|
|
|
8
9
|
interface VariableTagProps extends UnstableTagProps {
|
|
9
10
|
onUnlink?: () => void;
|
|
@@ -14,9 +15,11 @@ export const AssignedTag = ( { startIcon, label, onUnlink, ...props }: VariableT
|
|
|
14
15
|
|
|
15
16
|
if ( onUnlink ) {
|
|
16
17
|
actions.push(
|
|
17
|
-
<
|
|
18
|
-
<
|
|
19
|
-
|
|
18
|
+
<Tooltip key="unlink" title={ UNLINK_LABEL } placement="bottom">
|
|
19
|
+
<IconButton size={ SIZE } onClick={ onUnlink } aria-label={ UNLINK_LABEL }>
|
|
20
|
+
<DetachIcon fontSize={ SIZE } />
|
|
21
|
+
</IconButton>
|
|
22
|
+
</Tooltip>
|
|
20
23
|
);
|
|
21
24
|
}
|
|
22
25
|
|
|
@@ -5,7 +5,7 @@ import { useSuppressedMessage } from '@elementor/editor-current-user';
|
|
|
5
5
|
import { PopoverBody } from '@elementor/editor-editing-panel';
|
|
6
6
|
import { PopoverHeader } from '@elementor/editor-ui';
|
|
7
7
|
import { ArrowLeftIcon, TrashIcon } from '@elementor/icons';
|
|
8
|
-
import { Button, CardActions, Divider, FormHelperText, IconButton, Typography } from '@elementor/ui';
|
|
8
|
+
import { Button, CardActions, Divider, FormHelperText, IconButton, Tooltip, Typography } from '@elementor/ui';
|
|
9
9
|
import { __ } from '@wordpress/i18n';
|
|
10
10
|
|
|
11
11
|
import { useVariableType } from '../context/variable-type-context';
|
|
@@ -20,6 +20,7 @@ import { EDIT_CONFIRMATION_DIALOG_ID, EditConfirmationDialog } from './ui/edit-c
|
|
|
20
20
|
import { FormField } from './ui/form-field';
|
|
21
21
|
|
|
22
22
|
const SIZE = 'tiny';
|
|
23
|
+
const DELETE_LABEL = __( 'Delete variable', 'elementor' );
|
|
23
24
|
|
|
24
25
|
type Props = {
|
|
25
26
|
editId: string;
|
|
@@ -127,14 +128,11 @@ export const VariableEdit = ( { onClose, onGoBack, onSubmit, editId }: Props ) =
|
|
|
127
128
|
|
|
128
129
|
if ( userPermissions.canDelete() ) {
|
|
129
130
|
actions.push(
|
|
130
|
-
<
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
>
|
|
136
|
-
<TrashIcon fontSize={ SIZE } />
|
|
137
|
-
</IconButton>
|
|
131
|
+
<Tooltip key="delete" placement="top" title={ DELETE_LABEL }>
|
|
132
|
+
<IconButton size={ SIZE } onClick={ handleDeleteConfirmation } aria-label={ DELETE_LABEL }>
|
|
133
|
+
<TrashIcon fontSize={ SIZE } />
|
|
134
|
+
</IconButton>
|
|
135
|
+
</Tooltip>
|
|
138
136
|
);
|
|
139
137
|
}
|
|
140
138
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { useCallback, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface UseErrorNavigationReturn {
|
|
4
|
+
createNavigationCallback: (
|
|
5
|
+
ids: string[],
|
|
6
|
+
onNavigate: ( id: string ) => void,
|
|
7
|
+
onComplete: () => void
|
|
8
|
+
) => () => void;
|
|
9
|
+
resetNavigation: () => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const useErrorNavigation = (): UseErrorNavigationReturn => {
|
|
13
|
+
const currentIndexRef = useRef( 0 );
|
|
14
|
+
|
|
15
|
+
const createNavigationCallback = useCallback(
|
|
16
|
+
( ids: string[], onNavigate: ( id: string ) => void, onComplete: () => void ) => {
|
|
17
|
+
return () => {
|
|
18
|
+
if ( ! ids?.length ) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const currentIndex = currentIndexRef.current;
|
|
23
|
+
const currentId = ids[ currentIndex ];
|
|
24
|
+
|
|
25
|
+
if ( currentId ) {
|
|
26
|
+
onNavigate( currentId );
|
|
27
|
+
|
|
28
|
+
const nextIndex = currentIndex + 1;
|
|
29
|
+
if ( nextIndex >= ids.length ) {
|
|
30
|
+
onComplete();
|
|
31
|
+
currentIndexRef.current = 0;
|
|
32
|
+
} else {
|
|
33
|
+
currentIndexRef.current = nextIndex;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
[]
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const resetNavigation = useCallback( () => {
|
|
42
|
+
currentIndexRef.current = 0;
|
|
43
|
+
}, [] );
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
createNavigationCallback,
|
|
47
|
+
resetNavigation,
|
|
48
|
+
};
|
|
49
|
+
};
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
import { useCallback, useState } from 'react';
|
|
2
|
-
import { __ } from '@wordpress/i18n';
|
|
3
2
|
|
|
4
3
|
import { generateTempId } from '../../../batch-operations';
|
|
5
4
|
import { getVariables } from '../../../hooks/use-prop-variables';
|
|
6
5
|
import { service } from '../../../service';
|
|
7
6
|
import { type TVariablesList } from '../../../storage';
|
|
8
7
|
import { filterBySearch } from '../../../utils/filter-by-search';
|
|
9
|
-
import { ERROR_MESSAGES } from '../../../utils/validations';
|
|
10
8
|
|
|
11
9
|
export const useVariablesManagerState = () => {
|
|
12
10
|
const [ variables, setVariables ] = useState( () => getVariables( false ) );
|
|
13
11
|
const [ deletedVariables, setDeletedVariables ] = useState< string[] >( [] );
|
|
12
|
+
const [ isSaveDisabled, setIsSaveDisabled ] = useState( false );
|
|
14
13
|
const [ isDirty, setIsDirty ] = useState( false );
|
|
15
|
-
const [ hasValidationErrors, setHasValidationErrors ] = useState( false );
|
|
16
14
|
const [ isSaving, setIsSaving ] = useState( false );
|
|
17
15
|
const [ searchValue, setSearchValue ] = useState( '' );
|
|
18
16
|
|
|
@@ -49,28 +47,21 @@ export const useVariablesManagerState = () => {
|
|
|
49
47
|
setSearchValue( searchTerm );
|
|
50
48
|
};
|
|
51
49
|
|
|
52
|
-
const handleSave = useCallback( async (): Promise< { success: boolean
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const result = await service.batchSave( originalVariables, variables );
|
|
50
|
+
const handleSave = useCallback( async (): Promise< { success: boolean } > => {
|
|
51
|
+
const originalVariables = getVariables( false );
|
|
52
|
+
setIsSaving( true );
|
|
53
|
+
const result = await service.batchSave( originalVariables, variables );
|
|
57
54
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
55
|
+
if ( result.success ) {
|
|
56
|
+
await service.load();
|
|
57
|
+
const updatedVariables = service.variables();
|
|
61
58
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
setIsSaving( false );
|
|
66
|
-
return { success: true };
|
|
67
|
-
}
|
|
68
|
-
throw new Error( __( 'Failed to save variables. Please try again.', 'elementor' ) );
|
|
69
|
-
} catch ( error ) {
|
|
70
|
-
const errorMessage = error instanceof Error ? error.message : ERROR_MESSAGES.UNEXPECTED_ERROR;
|
|
71
|
-
setIsSaving( false );
|
|
72
|
-
return { success: false, error: errorMessage };
|
|
59
|
+
setVariables( updatedVariables );
|
|
60
|
+
setDeletedVariables( [] );
|
|
61
|
+
setIsDirty( false );
|
|
73
62
|
}
|
|
63
|
+
|
|
64
|
+
return { success: result.success };
|
|
74
65
|
}, [ variables ] );
|
|
75
66
|
|
|
76
67
|
const filteredVariables = () => {
|
|
@@ -84,7 +75,7 @@ export const useVariablesManagerState = () => {
|
|
|
84
75
|
variables: filteredVariables(),
|
|
85
76
|
deletedVariables,
|
|
86
77
|
isDirty,
|
|
87
|
-
|
|
78
|
+
isSaveDisabled,
|
|
88
79
|
handleOnChange,
|
|
89
80
|
createVariable,
|
|
90
81
|
handleDeleteVariable,
|
|
@@ -92,6 +83,7 @@ export const useVariablesManagerState = () => {
|
|
|
92
83
|
isSaving,
|
|
93
84
|
handleSearch,
|
|
94
85
|
searchValue,
|
|
95
|
-
|
|
86
|
+
setIsSaving,
|
|
87
|
+
setIsSaveDisabled,
|
|
96
88
|
};
|
|
97
89
|
};
|
|
@@ -10,14 +10,26 @@ import {
|
|
|
10
10
|
} from '@elementor/editor-panels';
|
|
11
11
|
import { SaveChangesDialog, SearchField, ThemeProvider, useDialog } from '@elementor/editor-ui';
|
|
12
12
|
import { changeEditMode } from '@elementor/editor-v1-adapters';
|
|
13
|
-
import { ColorFilterIcon, TrashIcon } from '@elementor/icons';
|
|
14
|
-
import {
|
|
13
|
+
import { AlertTriangleFilledIcon, ColorFilterIcon, TrashIcon } from '@elementor/icons';
|
|
14
|
+
import {
|
|
15
|
+
Alert,
|
|
16
|
+
AlertAction,
|
|
17
|
+
AlertTitle,
|
|
18
|
+
Button,
|
|
19
|
+
CloseButton,
|
|
20
|
+
Divider,
|
|
21
|
+
Infotip,
|
|
22
|
+
Stack,
|
|
23
|
+
usePopupState,
|
|
24
|
+
} from '@elementor/ui';
|
|
15
25
|
import { __ } from '@wordpress/i18n';
|
|
16
26
|
|
|
27
|
+
import { type ErrorResponse, type MappedError, mapServerError } from '../../utils/validations';
|
|
17
28
|
import { DeleteConfirmationDialog } from '../ui/delete-confirmation-dialog';
|
|
18
29
|
import { EmptyState } from '../ui/empty-state';
|
|
19
30
|
import { NoSearchResults } from '../ui/no-search-results';
|
|
20
31
|
import { useAutoEdit } from './hooks/use-auto-edit';
|
|
32
|
+
import { useErrorNavigation } from './hooks/use-error-navigation';
|
|
21
33
|
import { useVariablesManagerState } from './hooks/use-variables-manager-state';
|
|
22
34
|
import { SIZE, VariableManagerCreateMenu } from './variables-manager-create-menu';
|
|
23
35
|
import { VariablesManagerTable } from './variables-manager-table';
|
|
@@ -47,20 +59,23 @@ export function VariablesManagerPanel() {
|
|
|
47
59
|
const {
|
|
48
60
|
variables,
|
|
49
61
|
isDirty,
|
|
50
|
-
hasValidationErrors,
|
|
51
62
|
searchValue,
|
|
63
|
+
isSaveDisabled,
|
|
52
64
|
handleOnChange,
|
|
53
65
|
createVariable,
|
|
54
66
|
handleDeleteVariable,
|
|
55
67
|
handleSave,
|
|
56
68
|
isSaving,
|
|
57
69
|
handleSearch,
|
|
58
|
-
|
|
70
|
+
setIsSaving,
|
|
71
|
+
setIsSaveDisabled,
|
|
59
72
|
} = useVariablesManagerState();
|
|
60
73
|
|
|
61
74
|
const { autoEditVariableId, startAutoEdit, handleAutoEditComplete } = useAutoEdit();
|
|
75
|
+
const { createNavigationCallback, resetNavigation } = useErrorNavigation();
|
|
62
76
|
|
|
63
77
|
const [ deleteConfirmation, setDeleteConfirmation ] = useState< { id: string; label: string } | null >( null );
|
|
78
|
+
const [ serverError, setServerError ] = useState< MappedError | null >( null );
|
|
64
79
|
|
|
65
80
|
usePreventUnload( isDirty );
|
|
66
81
|
|
|
@@ -83,6 +98,32 @@ export function VariablesManagerPanel() {
|
|
|
83
98
|
[ createVariable, startAutoEdit ]
|
|
84
99
|
);
|
|
85
100
|
|
|
101
|
+
const handleSaveClick = async () => {
|
|
102
|
+
try {
|
|
103
|
+
setServerError( null );
|
|
104
|
+
resetNavigation();
|
|
105
|
+
|
|
106
|
+
return await handleSave();
|
|
107
|
+
} catch ( error ) {
|
|
108
|
+
const mappedError = mapServerError( error as ErrorResponse );
|
|
109
|
+
const duplicatedIds = mappedError?.action?.data?.duplicatedIds;
|
|
110
|
+
|
|
111
|
+
if ( mappedError && 'label' === mappedError.field ) {
|
|
112
|
+
if ( duplicatedIds && mappedError.action ) {
|
|
113
|
+
mappedError.action.callback = createNavigationCallback( duplicatedIds, startAutoEdit, () => {
|
|
114
|
+
setIsSaveDisabled( false );
|
|
115
|
+
} );
|
|
116
|
+
}
|
|
117
|
+
setServerError( mappedError );
|
|
118
|
+
setIsSaveDisabled( true );
|
|
119
|
+
resetNavigation();
|
|
120
|
+
}
|
|
121
|
+
return { success: false, error: mappedError };
|
|
122
|
+
} finally {
|
|
123
|
+
setIsSaving( false );
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
86
127
|
const handleDeleteVariableWithConfirmation = useCallback(
|
|
87
128
|
( itemId: string ) => {
|
|
88
129
|
handleDeleteVariable( itemId );
|
|
@@ -108,113 +149,145 @@ export function VariablesManagerPanel() {
|
|
|
108
149
|
|
|
109
150
|
return (
|
|
110
151
|
<ThemeProvider>
|
|
111
|
-
<
|
|
112
|
-
<
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
>
|
|
118
|
-
<Stack width="100%" direction="
|
|
119
|
-
<Stack p={ 1 } pl={ 2 } width="100%" direction="row" alignItems="center">
|
|
120
|
-
<Stack width="100%" direction="row" gap={ 1 }>
|
|
121
|
-
<PanelHeaderTitle sx={ { display: 'flex', alignItems: 'center', gap: 0.5 } }>
|
|
122
|
-
<ColorFilterIcon fontSize="inherit" />
|
|
123
|
-
{ __( 'Variable Manager', 'elementor' ) }
|
|
124
|
-
</PanelHeaderTitle>
|
|
125
|
-
</Stack>
|
|
126
|
-
<Stack direction="row" gap={ 0.5 } alignItems="center">
|
|
127
|
-
<VariableManagerCreateMenu
|
|
128
|
-
onCreate={ handleCreateVariable }
|
|
129
|
-
variables={ variables }
|
|
130
|
-
menuState={ createMenuState }
|
|
131
|
-
/>
|
|
132
|
-
<CloseButton
|
|
133
|
-
aria-label="Close"
|
|
134
|
-
slotProps={ { icon: { fontSize: SIZE } } }
|
|
135
|
-
onClick={ () => {
|
|
136
|
-
handleClosePanel();
|
|
137
|
-
} }
|
|
138
|
-
/>
|
|
139
|
-
</Stack>
|
|
140
|
-
</Stack>
|
|
152
|
+
<Panel>
|
|
153
|
+
<PanelHeader
|
|
154
|
+
sx={ {
|
|
155
|
+
height: 'unset',
|
|
156
|
+
} }
|
|
157
|
+
>
|
|
158
|
+
<Stack width="100%" direction="column" alignItems="center">
|
|
159
|
+
<Stack p={ 1 } pl={ 2 } width="100%" direction="row" alignItems="center">
|
|
141
160
|
<Stack width="100%" direction="row" gap={ 1 }>
|
|
142
|
-
<
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
161
|
+
<PanelHeaderTitle sx={ { display: 'flex', alignItems: 'center', gap: 0.5 } }>
|
|
162
|
+
<ColorFilterIcon fontSize="inherit" />
|
|
163
|
+
{ __( 'Variable Manager', 'elementor' ) }
|
|
164
|
+
</PanelHeaderTitle>
|
|
165
|
+
</Stack>
|
|
166
|
+
<Stack direction="row" gap={ 0.5 } alignItems="center">
|
|
167
|
+
<VariableManagerCreateMenu
|
|
168
|
+
onCreate={ handleCreateVariable }
|
|
169
|
+
variables={ variables }
|
|
170
|
+
menuState={ createMenuState }
|
|
171
|
+
/>
|
|
172
|
+
<CloseButton
|
|
173
|
+
aria-label="Close"
|
|
174
|
+
slotProps={ { icon: { fontSize: SIZE } } }
|
|
175
|
+
onClick={ () => {
|
|
176
|
+
handleClosePanel();
|
|
146
177
|
} }
|
|
147
|
-
placeholder={ __( 'Search', 'elementor' ) }
|
|
148
|
-
value={ searchValue }
|
|
149
|
-
onSearch={ handleSearch }
|
|
150
178
|
/>
|
|
151
179
|
</Stack>
|
|
152
|
-
<Divider sx={ { width: '100%' } } />
|
|
153
180
|
</Stack>
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
<VariablesManagerTable
|
|
164
|
-
menuActions={ menuActions }
|
|
165
|
-
variables={ variables }
|
|
166
|
-
onChange={ handleOnChange }
|
|
167
|
-
autoEditVariableId={ autoEditVariableId }
|
|
168
|
-
onAutoEditComplete={ handleAutoEditComplete }
|
|
169
|
-
onFieldError={ setHasValidationErrors }
|
|
181
|
+
<Stack width="100%" direction="row" gap={ 1 }>
|
|
182
|
+
<SearchField
|
|
183
|
+
sx={ {
|
|
184
|
+
display: 'flex',
|
|
185
|
+
flex: 1,
|
|
186
|
+
} }
|
|
187
|
+
placeholder={ __( 'Search', 'elementor' ) }
|
|
188
|
+
value={ searchValue }
|
|
189
|
+
onSearch={ handleSearch }
|
|
170
190
|
/>
|
|
171
|
-
|
|
191
|
+
</Stack>
|
|
192
|
+
<Divider sx={ { width: '100%' } } />
|
|
193
|
+
</Stack>
|
|
194
|
+
</PanelHeader>
|
|
195
|
+
<PanelBody
|
|
196
|
+
sx={ {
|
|
197
|
+
display: 'flex',
|
|
198
|
+
flexDirection: 'column',
|
|
199
|
+
height: '100%',
|
|
200
|
+
} }
|
|
201
|
+
>
|
|
202
|
+
{ hasVariables && (
|
|
203
|
+
<VariablesManagerTable
|
|
204
|
+
menuActions={ menuActions }
|
|
205
|
+
variables={ variables }
|
|
206
|
+
onChange={ handleOnChange }
|
|
207
|
+
autoEditVariableId={ autoEditVariableId }
|
|
208
|
+
onAutoEditComplete={ handleAutoEditComplete }
|
|
209
|
+
onFieldError={ setIsSaveDisabled }
|
|
210
|
+
/>
|
|
211
|
+
) }
|
|
172
212
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
213
|
+
{ ! hasVariables && searchValue && (
|
|
214
|
+
<NoSearchResults
|
|
215
|
+
searchValue={ searchValue }
|
|
216
|
+
onClear={ () => handleSearch( '' ) }
|
|
217
|
+
icon={ <ColorFilterIcon fontSize="large" /> }
|
|
218
|
+
/>
|
|
219
|
+
) }
|
|
180
220
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
221
|
+
{ ! hasVariables && ! searchValue && (
|
|
222
|
+
<EmptyState
|
|
223
|
+
title={ __( 'Create your first variable', 'elementor' ) }
|
|
224
|
+
message={ __(
|
|
225
|
+
'Variables are saved attributes that you can apply anywhere on your site.',
|
|
226
|
+
'elementor'
|
|
227
|
+
) }
|
|
228
|
+
icon={ <ColorFilterIcon fontSize="large" /> }
|
|
229
|
+
onAdd={ createMenuState.open }
|
|
230
|
+
/>
|
|
231
|
+
) }
|
|
232
|
+
</PanelBody>
|
|
193
233
|
|
|
194
|
-
|
|
234
|
+
<PanelFooter>
|
|
235
|
+
<Infotip
|
|
236
|
+
placement="right"
|
|
237
|
+
open={ !! serverError }
|
|
238
|
+
content={
|
|
239
|
+
serverError ? (
|
|
240
|
+
<Alert
|
|
241
|
+
severity="error"
|
|
242
|
+
action={
|
|
243
|
+
serverError.action ? (
|
|
244
|
+
<AlertAction onClick={ serverError.action.callback }>
|
|
245
|
+
{ serverError.action.label }
|
|
246
|
+
</AlertAction>
|
|
247
|
+
) : undefined
|
|
248
|
+
}
|
|
249
|
+
icon={ <AlertTriangleFilledIcon /> }
|
|
250
|
+
>
|
|
251
|
+
<AlertTitle>{ serverError.message }</AlertTitle>
|
|
252
|
+
{ serverError.action?.message }
|
|
253
|
+
</Alert>
|
|
254
|
+
) : null
|
|
255
|
+
}
|
|
256
|
+
arrow={ false }
|
|
257
|
+
slotProps={ {
|
|
258
|
+
popper: {
|
|
259
|
+
modifiers: [
|
|
260
|
+
{
|
|
261
|
+
name: 'offset',
|
|
262
|
+
options: { offset: [ -10, 10 ] },
|
|
263
|
+
},
|
|
264
|
+
],
|
|
265
|
+
},
|
|
266
|
+
} }
|
|
267
|
+
>
|
|
195
268
|
<Button
|
|
196
269
|
fullWidth
|
|
197
270
|
size="small"
|
|
198
271
|
color="global"
|
|
199
272
|
variant="contained"
|
|
200
|
-
disabled={ ! isDirty ||
|
|
201
|
-
onClick={
|
|
273
|
+
disabled={ isSaveDisabled || ! isDirty || isSaving }
|
|
274
|
+
onClick={ handleSaveClick }
|
|
202
275
|
loading={ isSaving }
|
|
203
276
|
>
|
|
204
277
|
{ __( 'Save changes', 'elementor' ) }
|
|
205
278
|
</Button>
|
|
206
|
-
</
|
|
207
|
-
</
|
|
279
|
+
</Infotip>
|
|
280
|
+
</PanelFooter>
|
|
281
|
+
</Panel>
|
|
208
282
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
</ErrorBoundary>
|
|
283
|
+
{ deleteConfirmation && (
|
|
284
|
+
<DeleteConfirmationDialog
|
|
285
|
+
open
|
|
286
|
+
label={ deleteConfirmation.label }
|
|
287
|
+
onConfirm={ () => handleDeleteVariableWithConfirmation( deleteConfirmation.id ) }
|
|
288
|
+
closeDialog={ () => setDeleteConfirmation( null ) }
|
|
289
|
+
/>
|
|
290
|
+
) }
|
|
218
291
|
|
|
219
292
|
{ isSaveChangesDialogOpen && (
|
|
220
293
|
<SaveChangesDialog>
|
|
@@ -238,9 +311,11 @@ export function VariablesManagerPanel() {
|
|
|
238
311
|
confirm: {
|
|
239
312
|
label: __( 'Save', 'elementor' ),
|
|
240
313
|
action: async () => {
|
|
241
|
-
await
|
|
314
|
+
const result = await handleSaveClick();
|
|
242
315
|
closeSaveChangesDialog();
|
|
243
|
-
|
|
316
|
+
if ( result?.success ) {
|
|
317
|
+
closePanel();
|
|
318
|
+
}
|
|
244
319
|
},
|
|
245
320
|
},
|
|
246
321
|
} }
|
|
@@ -251,14 +326,6 @@ export function VariablesManagerPanel() {
|
|
|
251
326
|
);
|
|
252
327
|
}
|
|
253
328
|
|
|
254
|
-
const ErrorBoundaryFallback = () => (
|
|
255
|
-
<Box role="alert" sx={ { minHeight: '100%', p: 2 } }>
|
|
256
|
-
<Alert severity="error" sx={ { mb: 2, maxWidth: 400, textAlign: 'center' } }>
|
|
257
|
-
<strong>{ __( 'Something went wrong', 'elementor' ) }</strong>
|
|
258
|
-
</Alert>
|
|
259
|
-
</Box>
|
|
260
|
-
);
|
|
261
|
-
|
|
262
329
|
const usePreventUnload = ( isDirty: boolean ) => {
|
|
263
330
|
useEffect( () => {
|
|
264
331
|
const handleBeforeUnload = ( event: BeforeUnloadEvent ) => {
|