@elementor/editor-variables 3.33.0-98 → 3.34.2
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.d.mts +11 -3
- package/dist/index.d.ts +11 -3
- package/dist/index.js +1874 -801
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1819 -737
- package/dist/index.mjs.map +1 -1
- package/package.json +16 -14
- package/src/api.ts +24 -0
- package/src/batch-operations.ts +86 -0
- package/src/components/fields/color-field.tsx +1 -0
- package/src/components/fields/font-field.tsx +2 -1
- package/src/components/fields/label-field.tsx +42 -6
- package/src/components/ui/deleted-variable-alert.tsx +14 -10
- package/src/components/ui/{no-variables.tsx → empty-state.tsx} +8 -13
- package/src/components/ui/menu-item-content.tsx +14 -11
- package/src/components/ui/mismatch-variable-alert.tsx +5 -9
- package/src/components/ui/missing-variable-alert.tsx +8 -9
- package/src/components/ui/no-search-results.tsx +1 -2
- package/src/components/ui/tags/assigned-tag.tsx +6 -3
- package/src/components/ui/tags/warning-variable-tag.tsx +44 -0
- package/src/components/ui/variable/deleted-variable.tsx +13 -6
- package/src/components/ui/variable/mismatch-variable.tsx +11 -4
- package/src/components/ui/variable/missing-variable.tsx +2 -2
- package/src/components/variable-creation.tsx +10 -3
- package/src/components/variable-edit.tsx +11 -12
- package/src/components/variable-restore.tsx +3 -2
- package/src/components/variables-manager/hooks/use-auto-edit.ts +21 -0
- package/src/components/variables-manager/hooks/use-error-navigation.ts +49 -0
- package/src/components/variables-manager/hooks/use-variables-manager-state.ts +89 -0
- package/src/components/variables-manager/variable-editable-cell.tsx +131 -67
- package/src/components/variables-manager/variables-manager-create-menu.tsx +116 -0
- package/src/components/variables-manager/variables-manager-panel.tsx +290 -59
- package/src/components/variables-manager/variables-manager-table.tsx +111 -14
- package/src/components/variables-selection.tsx +61 -15
- package/src/controls/variable-control.tsx +1 -1
- package/src/hooks/use-prop-variables.ts +11 -8
- package/src/hooks/use-variable-bound-prop.ts +42 -0
- package/src/index.ts +1 -0
- package/src/init.ts +19 -6
- package/src/mcp/create-variable-tool.ts +70 -0
- package/src/mcp/delete-variable-tool.ts +50 -0
- package/src/mcp/index.ts +17 -0
- package/src/mcp/list-variables-tool.ts +58 -0
- package/src/mcp/update-variable-tool.ts +81 -0
- package/src/mcp/variables-resource.ts +28 -0
- package/src/register-variable-types.tsx +2 -0
- package/src/service.ts +60 -1
- package/src/storage.ts +8 -0
- package/src/types.ts +1 -0
- package/src/utils/filter-by-search.ts +5 -0
- package/src/utils/tracking.ts +37 -22
- package/src/utils/validations.ts +72 -3
- package/src/variables-registry/create-variable-type-registry.ts +10 -1
- package/src/variables-registry/variable-type-registry.ts +2 -1
- package/src/components/ui/tags/deleted-tag.tsx +0 -37
- package/src/components/ui/tags/mismatch-tag.tsx +0 -37
- package/src/components/ui/tags/missing-tag.tsx +0 -25
- /package/src/components/variables-manager/{variable-edit-menu.tsx → ui/variable-edit-menu.tsx} +0 -0
- /package/src/components/variables-manager/{variable-table-cell.tsx → ui/variable-table-cell.tsx} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-variables",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.34.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "Elementor Team",
|
|
6
6
|
"homepage": "https://elementor.com/",
|
|
@@ -39,19 +39,21 @@
|
|
|
39
39
|
"dev": "tsup --config=../../tsup.dev.ts"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@elementor/editor": "3.
|
|
43
|
-
"@elementor/editor-canvas": "3.
|
|
44
|
-
"@elementor/editor-controls": "3.
|
|
45
|
-
"@elementor/editor-current-user": "3.
|
|
46
|
-
"@elementor/editor-editing-panel": "3.
|
|
47
|
-
"@elementor/editor-
|
|
48
|
-
"@elementor/editor-
|
|
49
|
-
"@elementor/editor-
|
|
50
|
-
"@elementor/editor-
|
|
51
|
-
"@elementor/
|
|
52
|
-
"@elementor/
|
|
53
|
-
"@elementor/
|
|
54
|
-
"@elementor/
|
|
42
|
+
"@elementor/editor": "3.34.2",
|
|
43
|
+
"@elementor/editor-canvas": "3.34.2",
|
|
44
|
+
"@elementor/editor-controls": "3.34.2",
|
|
45
|
+
"@elementor/editor-current-user": "3.34.2",
|
|
46
|
+
"@elementor/editor-editing-panel": "3.34.2",
|
|
47
|
+
"@elementor/editor-mcp": "3.34.2",
|
|
48
|
+
"@elementor/editor-panels": "3.34.2",
|
|
49
|
+
"@elementor/editor-props": "3.34.2",
|
|
50
|
+
"@elementor/editor-ui": "3.34.2",
|
|
51
|
+
"@elementor/editor-v1-adapters": "3.34.2",
|
|
52
|
+
"@elementor/http-client": "3.34.2",
|
|
53
|
+
"@elementor/icons": "^1.61.0",
|
|
54
|
+
"@elementor/mixpanel": "3.34.2",
|
|
55
|
+
"@elementor/schema": "3.34.2",
|
|
56
|
+
"@elementor/ui": "1.36.17",
|
|
55
57
|
"@wordpress/i18n": "^5.13.0"
|
|
56
58
|
},
|
|
57
59
|
"peerDependencies": {
|
package/src/api.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { httpService } from '@elementor/http-client';
|
|
2
2
|
|
|
3
|
+
import { type OperationType } from './batch-operations';
|
|
4
|
+
|
|
3
5
|
const BASE_PATH = 'elementor/v1/variables';
|
|
4
6
|
|
|
5
7
|
type RestoreVariablePayload = {
|
|
@@ -8,6 +10,24 @@ type RestoreVariablePayload = {
|
|
|
8
10
|
value?: string;
|
|
9
11
|
};
|
|
10
12
|
|
|
13
|
+
export type BatchOperation = {
|
|
14
|
+
type: OperationType;
|
|
15
|
+
id?: string;
|
|
16
|
+
variable?: {
|
|
17
|
+
id?: string;
|
|
18
|
+
type?: string;
|
|
19
|
+
label?: string;
|
|
20
|
+
value?: string;
|
|
21
|
+
};
|
|
22
|
+
label?: string;
|
|
23
|
+
value?: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type BatchPayload = {
|
|
27
|
+
watermark: number;
|
|
28
|
+
operations: BatchOperation[];
|
|
29
|
+
};
|
|
30
|
+
|
|
11
31
|
export const apiClient = {
|
|
12
32
|
list: () => {
|
|
13
33
|
return httpService().get( BASE_PATH + '/list' );
|
|
@@ -46,4 +66,8 @@ export const apiClient = {
|
|
|
46
66
|
|
|
47
67
|
return httpService().post( BASE_PATH + '/restore', payload );
|
|
48
68
|
},
|
|
69
|
+
|
|
70
|
+
batch: ( payload: BatchPayload ) => {
|
|
71
|
+
return httpService().post( BASE_PATH + '/batch', payload );
|
|
72
|
+
},
|
|
49
73
|
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { type BatchOperation } from './api';
|
|
2
|
+
import { type TVariable, type TVariablesList } from './storage';
|
|
3
|
+
|
|
4
|
+
export type OperationType = 'create' | 'update' | 'delete' | 'restore';
|
|
5
|
+
|
|
6
|
+
export type OperationResult = {
|
|
7
|
+
id: string;
|
|
8
|
+
type: OperationType;
|
|
9
|
+
variable?: TVariable & { id: string };
|
|
10
|
+
deleted?: boolean;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const generateTempId = (): string => {
|
|
14
|
+
const timestamp = Date.now().toString( 36 );
|
|
15
|
+
const random = Math.random().toString( 36 ).substring( 2, 8 );
|
|
16
|
+
return `tmp-${ timestamp }-${ random }`;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const isTempId = ( id: string ): boolean => {
|
|
20
|
+
return id.startsWith( 'tmp-' );
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const buildOperationsArray = (
|
|
24
|
+
originalVariables: TVariablesList,
|
|
25
|
+
currentVariables: TVariablesList
|
|
26
|
+
): BatchOperation[] => {
|
|
27
|
+
const operations: BatchOperation[] = [];
|
|
28
|
+
|
|
29
|
+
Object.entries( currentVariables ).forEach( ( [ id, variable ] ) => {
|
|
30
|
+
if ( isTempId( id ) ) {
|
|
31
|
+
operations.push( {
|
|
32
|
+
type: 'create',
|
|
33
|
+
variable: {
|
|
34
|
+
...variable,
|
|
35
|
+
id,
|
|
36
|
+
},
|
|
37
|
+
} );
|
|
38
|
+
} else if ( originalVariables[ id ] ) {
|
|
39
|
+
const original = originalVariables[ id ];
|
|
40
|
+
|
|
41
|
+
if ( original.deleted && ! variable.deleted ) {
|
|
42
|
+
operations.push( {
|
|
43
|
+
type: 'restore',
|
|
44
|
+
id,
|
|
45
|
+
...( original.label !== variable.label && { label: variable.label } ),
|
|
46
|
+
...( original.value !== variable.value && { value: variable.value } ),
|
|
47
|
+
} );
|
|
48
|
+
} else if (
|
|
49
|
+
! variable.deleted &&
|
|
50
|
+
( original.label !== variable.label ||
|
|
51
|
+
original.value !== variable.value ||
|
|
52
|
+
original.order !== variable.order )
|
|
53
|
+
) {
|
|
54
|
+
operations.push( {
|
|
55
|
+
type: 'update',
|
|
56
|
+
id,
|
|
57
|
+
variable: {
|
|
58
|
+
...( original.label !== variable.label && { label: variable.label } ),
|
|
59
|
+
...( original.value !== variable.value && { value: variable.value } ),
|
|
60
|
+
...( original.order !== variable.order && { order: variable.order } ),
|
|
61
|
+
},
|
|
62
|
+
} );
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
} );
|
|
66
|
+
|
|
67
|
+
Object.entries( originalVariables ).forEach( ( [ id, variable ] ) => {
|
|
68
|
+
if ( isTempId( id ) || variable.deleted ) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const currentVariable = currentVariables[ id ];
|
|
73
|
+
|
|
74
|
+
if ( ! currentVariable || currentVariable.deleted ) {
|
|
75
|
+
operations.push( {
|
|
76
|
+
type: 'delete',
|
|
77
|
+
id,
|
|
78
|
+
} );
|
|
79
|
+
}
|
|
80
|
+
} );
|
|
81
|
+
|
|
82
|
+
return operations.filter( ( op ) => {
|
|
83
|
+
const id = op.id || op.variable?.id;
|
|
84
|
+
return id && ! ( isTempId( id ) && currentVariables[ id ]?.deleted );
|
|
85
|
+
} );
|
|
86
|
+
};
|
|
@@ -68,12 +68,13 @@ export const FontField = ( { value, onChange, onValidationChange }: FontFieldPro
|
|
|
68
68
|
{ ...bindPopover( fontPopoverState ) }
|
|
69
69
|
>
|
|
70
70
|
<ItemSelector
|
|
71
|
+
id="font-family-variables-selector"
|
|
71
72
|
itemsList={ mapFontSubs }
|
|
72
73
|
selectedItem={ fontFamily }
|
|
73
74
|
onItemChange={ handleFontFamilyChange }
|
|
74
75
|
onClose={ fontPopoverState.close }
|
|
75
76
|
sectionWidth={ sectionWidth }
|
|
76
|
-
title={ __( 'Font
|
|
77
|
+
title={ __( 'Font family', 'elementor' ) }
|
|
77
78
|
itemStyle={ ( item ) => ( { fontFamily: item.value } ) }
|
|
78
79
|
onDebounce={ enqueueFont }
|
|
79
80
|
icon={ TextIcon as React.ElementType< { fontSize: string } > }
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { useState } from 'react';
|
|
2
|
+
import { useRef, useState } from 'react';
|
|
3
|
+
import { WarningInfotip } from '@elementor/editor-ui';
|
|
3
4
|
import { TextField, type TextFieldProps } from '@elementor/ui';
|
|
4
5
|
|
|
5
|
-
import {
|
|
6
|
+
import { type TVariablesList } from '../../storage';
|
|
7
|
+
import { labelHint, validateLabel, VARIABLE_LABEL_MAX_LENGTH } from '../../utils/validations';
|
|
6
8
|
function isLabelEqual( a: string, b: string ) {
|
|
7
9
|
return a.trim().toLowerCase() === b.trim().toLowerCase();
|
|
8
10
|
}
|
|
@@ -21,7 +23,7 @@ export const useLabelError = ( initialError?: LabelErrorProps ) => {
|
|
|
21
23
|
};
|
|
22
24
|
};
|
|
23
25
|
|
|
24
|
-
type LabelFieldProps = {
|
|
26
|
+
export type LabelFieldProps = {
|
|
25
27
|
value: string;
|
|
26
28
|
error?: LabelErrorProps;
|
|
27
29
|
onChange: ( value: string ) => void;
|
|
@@ -29,6 +31,9 @@ type LabelFieldProps = {
|
|
|
29
31
|
onErrorChange?: ( errorMsg: string ) => void;
|
|
30
32
|
size?: TextFieldProps[ 'size' ];
|
|
31
33
|
focusOnShow?: boolean;
|
|
34
|
+
selectOnShow?: boolean;
|
|
35
|
+
showWarningInfotip?: boolean;
|
|
36
|
+
variables?: TVariablesList;
|
|
32
37
|
};
|
|
33
38
|
|
|
34
39
|
export const LabelField = ( {
|
|
@@ -39,14 +44,19 @@ export const LabelField = ( {
|
|
|
39
44
|
onErrorChange,
|
|
40
45
|
size = 'tiny',
|
|
41
46
|
focusOnShow = false,
|
|
47
|
+
selectOnShow = false,
|
|
48
|
+
showWarningInfotip = false,
|
|
49
|
+
variables,
|
|
42
50
|
}: LabelFieldProps ) => {
|
|
43
51
|
const [ label, setLabel ] = useState( value );
|
|
44
52
|
const [ errorMessage, setErrorMessage ] = useState( '' );
|
|
45
53
|
|
|
54
|
+
const fieldRef = useRef< HTMLElement >( null );
|
|
55
|
+
|
|
46
56
|
const handleChange = ( newValue: string ) => {
|
|
47
57
|
setLabel( newValue );
|
|
48
58
|
|
|
49
|
-
const errorMsg = validateLabel( newValue );
|
|
59
|
+
const errorMsg = validateLabel( newValue, variables );
|
|
50
60
|
|
|
51
61
|
setErrorMessage( errorMsg );
|
|
52
62
|
onErrorChange?.( errorMsg );
|
|
@@ -59,17 +69,43 @@ export const LabelField = ( {
|
|
|
59
69
|
errorMsg = error.message;
|
|
60
70
|
}
|
|
61
71
|
|
|
62
|
-
|
|
72
|
+
const hintMsg = ! errorMsg ? labelHint( label ) : '';
|
|
73
|
+
|
|
74
|
+
const textField = (
|
|
63
75
|
<TextField
|
|
76
|
+
ref={ fieldRef }
|
|
64
77
|
id={ id }
|
|
65
78
|
size={ size }
|
|
66
79
|
fullWidth
|
|
67
80
|
value={ label }
|
|
68
81
|
error={ !! errorMsg }
|
|
69
82
|
onChange={ ( e: React.ChangeEvent< HTMLInputElement > ) => handleChange( e.target.value ) }
|
|
70
|
-
inputProps={ {
|
|
83
|
+
inputProps={ {
|
|
84
|
+
maxLength: VARIABLE_LABEL_MAX_LENGTH,
|
|
85
|
+
...( selectOnShow && { onFocus: ( e: React.FocusEvent< HTMLInputElement > ) => e.target.select() } ),
|
|
86
|
+
'aria-label': 'Name',
|
|
87
|
+
} }
|
|
71
88
|
// eslint-disable-next-line jsx-a11y/no-autofocus
|
|
72
89
|
autoFocus={ focusOnShow }
|
|
73
90
|
/>
|
|
74
91
|
);
|
|
92
|
+
|
|
93
|
+
if ( showWarningInfotip ) {
|
|
94
|
+
const tooltipWidth = Math.max( 240, fieldRef.current?.getBoundingClientRect().width ?? 240 );
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<WarningInfotip
|
|
98
|
+
open={ Boolean( errorMsg || hintMsg ) }
|
|
99
|
+
text={ errorMsg || hintMsg }
|
|
100
|
+
placement="bottom-start"
|
|
101
|
+
width={ tooltipWidth }
|
|
102
|
+
offset={ [ 0, -15 ] }
|
|
103
|
+
{ ...( hintMsg && { hasError: false } ) }
|
|
104
|
+
>
|
|
105
|
+
{ textField }
|
|
106
|
+
</WarningInfotip>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return textField;
|
|
75
111
|
};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import { Alert, AlertAction, AlertTitle, ClickAwayListener } from '@elementor/ui';
|
|
2
|
+
import { Alert, AlertAction, AlertTitle, ClickAwayListener, Typography } from '@elementor/ui';
|
|
4
3
|
import { __ } from '@wordpress/i18n';
|
|
5
4
|
|
|
6
5
|
type DeletedVariableAlertProps = {
|
|
@@ -11,8 +10,6 @@ type DeletedVariableAlertProps = {
|
|
|
11
10
|
};
|
|
12
11
|
|
|
13
12
|
export const DeletedVariableAlert = ( { onClose, onUnlink, onRestore, label }: DeletedVariableAlertProps ) => {
|
|
14
|
-
const sectionWidth = useSectionWidth();
|
|
15
|
-
|
|
16
13
|
return (
|
|
17
14
|
<ClickAwayListener onClickAway={ onClose }>
|
|
18
15
|
<Alert
|
|
@@ -33,14 +30,21 @@ export const DeletedVariableAlert = ( { onClose, onUnlink, onRestore, label }: D
|
|
|
33
30
|
) }
|
|
34
31
|
</>
|
|
35
32
|
}
|
|
36
|
-
sx={ {
|
|
33
|
+
sx={ { maxWidth: 300 } }
|
|
37
34
|
>
|
|
38
35
|
<AlertTitle>{ __( 'Deleted variable', 'elementor' ) }</AlertTitle>
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
'
|
|
43
|
-
|
|
36
|
+
<Typography variant="body2" color="textPrimary">
|
|
37
|
+
{ __( 'The variable', 'elementor' ) }
|
|
38
|
+
'
|
|
39
|
+
<Typography variant="body2" component="span" sx={ { lineBreak: 'anywhere' } }>
|
|
40
|
+
{ label }
|
|
41
|
+
</Typography>
|
|
42
|
+
'
|
|
43
|
+
{ __(
|
|
44
|
+
'has been deleted, but it is still referenced in this location. You may restore the variable or unlink it to assign a different value.',
|
|
45
|
+
'elementor'
|
|
46
|
+
) }
|
|
47
|
+
</Typography>
|
|
44
48
|
</Alert>
|
|
45
49
|
</ClickAwayListener>
|
|
46
50
|
);
|
|
@@ -6,33 +6,28 @@ import { usePermissions } from '../../hooks/use-permissions';
|
|
|
6
6
|
|
|
7
7
|
type Props = {
|
|
8
8
|
icon?: React.ReactNode;
|
|
9
|
-
title
|
|
9
|
+
title: string;
|
|
10
|
+
message: string;
|
|
10
11
|
onAdd?: () => void;
|
|
11
12
|
};
|
|
12
13
|
|
|
13
|
-
export const
|
|
14
|
+
export const EmptyState = ( { icon, title, message, onAdd }: Props ) => {
|
|
14
15
|
const canAdd = usePermissions().canAdd();
|
|
15
16
|
|
|
16
17
|
return (
|
|
17
18
|
<Stack
|
|
18
19
|
gap={ 1 }
|
|
19
20
|
alignItems="center"
|
|
20
|
-
justifyContent="
|
|
21
|
+
justifyContent="flex-start"
|
|
21
22
|
height="100%"
|
|
22
23
|
color="text.secondary"
|
|
23
|
-
sx={ { p: 2.5, pb: 5.5 } }
|
|
24
|
+
sx={ { p: 2.5, pt: 8, pb: 5.5 } }
|
|
24
25
|
>
|
|
25
26
|
{ icon }
|
|
26
27
|
|
|
27
28
|
{ canAdd ? (
|
|
28
29
|
<>
|
|
29
|
-
<
|
|
30
|
-
title={ title || __( 'Create your first variable', 'elementor' ) }
|
|
31
|
-
message={ __(
|
|
32
|
-
'Variables are saved attributes that you can apply anywhere on your site.',
|
|
33
|
-
'elementor'
|
|
34
|
-
) }
|
|
35
|
-
/>
|
|
30
|
+
<Content title={ title } message={ message } />
|
|
36
31
|
{ onAdd && (
|
|
37
32
|
<Button variant="outlined" color="secondary" size="small" onClick={ onAdd }>
|
|
38
33
|
{ __( 'Create a variable', 'elementor' ) }
|
|
@@ -40,7 +35,7 @@ export const NoVariables = ( { icon, title, onAdd }: Props ) => {
|
|
|
40
35
|
) }
|
|
41
36
|
</>
|
|
42
37
|
) : (
|
|
43
|
-
<
|
|
38
|
+
<Content
|
|
44
39
|
title={ __( 'There are no variables', 'elementor' ) }
|
|
45
40
|
message={ __( 'With your current role, you can only connect and detach variables.', 'elementor' ) }
|
|
46
41
|
/>
|
|
@@ -54,7 +49,7 @@ type NoVariablesContentProps = {
|
|
|
54
49
|
message: string;
|
|
55
50
|
};
|
|
56
51
|
|
|
57
|
-
function
|
|
52
|
+
function Content( { title, message }: NoVariablesContentProps ) {
|
|
58
53
|
return (
|
|
59
54
|
<>
|
|
60
55
|
<Typography align="center" variant="subtitle2">
|
|
@@ -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
|
);
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import { Alert, AlertAction, AlertTitle, ClickAwayListener } from '@elementor/ui';
|
|
2
|
+
import { Alert, AlertAction, AlertTitle, ClickAwayListener, Typography } from '@elementor/ui';
|
|
4
3
|
import { __ } from '@wordpress/i18n';
|
|
5
4
|
|
|
6
5
|
type AlertProps = {
|
|
@@ -22,8 +21,6 @@ const i18n = {
|
|
|
22
21
|
};
|
|
23
22
|
|
|
24
23
|
export const MismatchVariableAlert = ( { onClose, onClear, triggerSelect }: AlertProps ) => {
|
|
25
|
-
const sectionWidth = useSectionWidth();
|
|
26
|
-
|
|
27
24
|
return (
|
|
28
25
|
<ClickAwayListener onClickAway={ onClose }>
|
|
29
26
|
<Alert
|
|
@@ -44,13 +41,12 @@ export const MismatchVariableAlert = ( { onClose, onClear, triggerSelect }: Aler
|
|
|
44
41
|
) }
|
|
45
42
|
</>
|
|
46
43
|
}
|
|
47
|
-
sx={ {
|
|
48
|
-
width: sectionWidth,
|
|
49
|
-
minWidth: 300,
|
|
50
|
-
} }
|
|
44
|
+
sx={ { maxWidth: 300 } }
|
|
51
45
|
>
|
|
52
46
|
<AlertTitle>{ i18n.title }</AlertTitle>
|
|
53
|
-
|
|
47
|
+
<Typography variant="body2" color="textPrimary">
|
|
48
|
+
{ i18n.message }
|
|
49
|
+
</Typography>
|
|
54
50
|
</Alert>
|
|
55
51
|
</ClickAwayListener>
|
|
56
52
|
);
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import { Alert, AlertAction, AlertTitle, ClickAwayListener } from '@elementor/ui';
|
|
2
|
+
import { Alert, AlertAction, AlertTitle, ClickAwayListener, Typography } from '@elementor/ui';
|
|
4
3
|
import { __ } from '@wordpress/i18n';
|
|
5
4
|
|
|
6
5
|
type MissingVariableAlertProps = {
|
|
@@ -9,8 +8,6 @@ type MissingVariableAlertProps = {
|
|
|
9
8
|
};
|
|
10
9
|
|
|
11
10
|
export const MissingVariableAlert = ( { onClose, onClear }: MissingVariableAlertProps ) => {
|
|
12
|
-
const sectionWidth = useSectionWidth();
|
|
13
|
-
|
|
14
11
|
return (
|
|
15
12
|
<ClickAwayListener onClickAway={ onClose }>
|
|
16
13
|
<Alert
|
|
@@ -26,13 +23,15 @@ export const MissingVariableAlert = ( { onClose, onClear }: MissingVariableAlert
|
|
|
26
23
|
) }
|
|
27
24
|
</>
|
|
28
25
|
}
|
|
29
|
-
sx={ {
|
|
26
|
+
sx={ { maxWidth: 300 } }
|
|
30
27
|
>
|
|
31
28
|
<AlertTitle>{ __( 'This variable is missing', 'elementor' ) }</AlertTitle>
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
<Typography variant="body2" color="textPrimary">
|
|
30
|
+
{ __(
|
|
31
|
+
'It may have been deleted. Try clearing this field and select a different value or variable.',
|
|
32
|
+
'elementor'
|
|
33
|
+
) }
|
|
34
|
+
</Typography>
|
|
36
35
|
</Alert>
|
|
37
36
|
</ClickAwayListener>
|
|
38
37
|
);
|
|
@@ -14,10 +14,9 @@ export const NoSearchResults = ( { searchValue, onClear, icon }: Props ) => {
|
|
|
14
14
|
gap={ 1 }
|
|
15
15
|
alignItems="center"
|
|
16
16
|
justifyContent="center"
|
|
17
|
-
height="100%"
|
|
18
17
|
p={ 2.5 }
|
|
19
18
|
color="text.secondary"
|
|
20
|
-
sx={ { pb: 3.5 } }
|
|
19
|
+
sx={ { pb: 3.5, pt: 8 } }
|
|
21
20
|
>
|
|
22
21
|
{ icon }
|
|
23
22
|
<Typography align="center" variant="subtitle2">
|
|
@@ -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
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { AlertTriangleFilledIcon } from '@elementor/icons';
|
|
3
|
+
import { Box, Chip, type ChipProps, type Theme, Tooltip, Typography } from '@elementor/ui';
|
|
4
|
+
|
|
5
|
+
interface WarningVariableTagProps extends ChipProps {
|
|
6
|
+
label: string;
|
|
7
|
+
suffix?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const WarningVariableTag = React.forwardRef< HTMLDivElement, WarningVariableTagProps >(
|
|
11
|
+
( { label, suffix, onClick, icon, ...props }, ref ) => {
|
|
12
|
+
const displayText = suffix ? `${ label } (${ suffix })` : label;
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<Chip
|
|
16
|
+
ref={ ref }
|
|
17
|
+
size="tiny"
|
|
18
|
+
color="warning"
|
|
19
|
+
shape="rounded"
|
|
20
|
+
variant="standard"
|
|
21
|
+
onClick={ onClick }
|
|
22
|
+
icon={ <AlertTriangleFilledIcon /> }
|
|
23
|
+
label={
|
|
24
|
+
<Tooltip title={ displayText } placement="top">
|
|
25
|
+
<Box sx={ { display: 'inline-grid', minWidth: 0 } }>
|
|
26
|
+
<Typography variant="caption" noWrap sx={ { lineHeight: 1.34 } }>
|
|
27
|
+
{ displayText }
|
|
28
|
+
</Typography>
|
|
29
|
+
</Box>
|
|
30
|
+
</Tooltip>
|
|
31
|
+
}
|
|
32
|
+
sx={ {
|
|
33
|
+
height: ( theme: Theme ) => theme.spacing( 3.5 ),
|
|
34
|
+
borderRadius: ( theme: Theme ) => theme.spacing( 1 ),
|
|
35
|
+
justifyContent: 'flex-start',
|
|
36
|
+
width: '100%',
|
|
37
|
+
} }
|
|
38
|
+
{ ...props }
|
|
39
|
+
/>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
WarningVariableTag.displayName = 'WarningVariableTag';
|
|
@@ -3,16 +3,18 @@ import { useId, useRef, useState } from 'react';
|
|
|
3
3
|
import { useBoundProp } from '@elementor/editor-controls';
|
|
4
4
|
import { type PropTypeKey } from '@elementor/editor-props';
|
|
5
5
|
import { Backdrop, bindPopover, Box, Infotip, Popover, usePopupState } from '@elementor/ui';
|
|
6
|
+
import { __ } from '@wordpress/i18n';
|
|
6
7
|
|
|
7
8
|
import { VariableTypeProvider } from '../../../context/variable-type-context';
|
|
8
9
|
import { usePermissions } from '../../../hooks/use-permissions';
|
|
9
10
|
import { restoreVariable } from '../../../hooks/use-prop-variables';
|
|
11
|
+
import { resolveBoundPropAndSetValue } from '../../../hooks/use-variable-bound-prop';
|
|
10
12
|
import { type Variable } from '../../../types';
|
|
11
13
|
import { createUnlinkHandler } from '../../../utils/unlink-variable';
|
|
12
14
|
import { getVariableType } from '../../../variables-registry/variable-type-registry';
|
|
13
15
|
import { VariableRestore } from '../../variable-restore';
|
|
14
16
|
import { DeletedVariableAlert } from '../deleted-variable-alert';
|
|
15
|
-
import {
|
|
17
|
+
import { WarningVariableTag } from '../tags/warning-variable-tag';
|
|
16
18
|
|
|
17
19
|
type Props = {
|
|
18
20
|
variable: Variable;
|
|
@@ -27,7 +29,7 @@ type Handlers = {
|
|
|
27
29
|
export const DeletedVariable = ( { variable, propTypeKey }: Props ) => {
|
|
28
30
|
const { propTypeUtil } = getVariableType( propTypeKey );
|
|
29
31
|
|
|
30
|
-
const
|
|
32
|
+
const boundProp = useBoundProp();
|
|
31
33
|
|
|
32
34
|
const userPermissions = usePermissions();
|
|
33
35
|
|
|
@@ -46,7 +48,7 @@ export const DeletedVariable = ( { variable, propTypeKey }: Props ) => {
|
|
|
46
48
|
const handlers: Handlers = {};
|
|
47
49
|
|
|
48
50
|
if ( userPermissions.canUnlink() ) {
|
|
49
|
-
handlers.onUnlink = createUnlinkHandler( variable, propTypeKey, setValue );
|
|
51
|
+
handlers.onUnlink = createUnlinkHandler( variable, propTypeKey, boundProp.setValue );
|
|
50
52
|
}
|
|
51
53
|
|
|
52
54
|
if ( userPermissions.canRestore() ) {
|
|
@@ -56,8 +58,9 @@ export const DeletedVariable = ( { variable, propTypeKey }: Props ) => {
|
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
restoreVariable( variable.key )
|
|
59
|
-
.then( (
|
|
60
|
-
|
|
61
|
+
.then( ( id ) => {
|
|
62
|
+
resolveBoundPropAndSetValue( propTypeUtil.create( id ), boundProp );
|
|
63
|
+
|
|
61
64
|
closeInfotip();
|
|
62
65
|
} )
|
|
63
66
|
.catch( () => {
|
|
@@ -101,7 +104,11 @@ export const DeletedVariable = ( { variable, propTypeKey }: Props ) => {
|
|
|
101
104
|
},
|
|
102
105
|
} }
|
|
103
106
|
>
|
|
104
|
-
<
|
|
107
|
+
<WarningVariableTag
|
|
108
|
+
label={ variable.label }
|
|
109
|
+
onClick={ toggleInfotip }
|
|
110
|
+
suffix={ __( 'deleted', 'elementor' ) }
|
|
111
|
+
/>
|
|
105
112
|
</Infotip>
|
|
106
113
|
|
|
107
114
|
<Popover
|