@elementor/editor-variables 0.6.0 → 0.8.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.
- package/CHANGELOG.md +39 -0
- package/dist/index.js +157 -60
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +170 -59
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
- package/src/components/color-variable-creation.tsx +122 -0
- package/src/components/variables-selection-popover.tsx +31 -15
- package/src/hooks/use-prop-variables.ts +30 -4
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useRef, useState } from 'react';
|
|
3
|
+
import { useBoundProp } from '@elementor/editor-controls';
|
|
4
|
+
import { BrushIcon } from '@elementor/icons';
|
|
5
|
+
import {
|
|
6
|
+
bindPopover,
|
|
7
|
+
Box,
|
|
8
|
+
Button,
|
|
9
|
+
CardActions,
|
|
10
|
+
CloseButton,
|
|
11
|
+
Divider,
|
|
12
|
+
FormLabel,
|
|
13
|
+
Grid,
|
|
14
|
+
Popover,
|
|
15
|
+
type PopupState,
|
|
16
|
+
Stack,
|
|
17
|
+
TextField,
|
|
18
|
+
Typography,
|
|
19
|
+
UnstableColorField,
|
|
20
|
+
} from '@elementor/ui';
|
|
21
|
+
import { __ } from '@wordpress/i18n';
|
|
22
|
+
|
|
23
|
+
import { createVariable } from '../hooks/use-prop-variables';
|
|
24
|
+
import { colorVariablePropTypeUtil } from '../prop-types/color-variable-prop-type';
|
|
25
|
+
|
|
26
|
+
export const ColorVariableCreation = ( { popupState }: { popupState: PopupState } ) => {
|
|
27
|
+
const { setValue: setVariable } = useBoundProp( colorVariablePropTypeUtil );
|
|
28
|
+
|
|
29
|
+
const [ color, setColor ] = useState( '' );
|
|
30
|
+
const [ label, setLabel ] = useState( '' );
|
|
31
|
+
|
|
32
|
+
const anchorRef = useRef< HTMLDivElement >( null );
|
|
33
|
+
|
|
34
|
+
const resetFields = () => {
|
|
35
|
+
setColor( '' );
|
|
36
|
+
setLabel( '' );
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const closePopover = () => {
|
|
40
|
+
resetFields();
|
|
41
|
+
popupState.close();
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const handleCreate = () => {
|
|
45
|
+
const key = createVariable( colorVariablePropTypeUtil.key, { label, value: color } );
|
|
46
|
+
setVariable( key );
|
|
47
|
+
closePopover();
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const isInValidForm = () => {
|
|
51
|
+
return ! color?.trim() || ! label?.trim();
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<Box ref={ anchorRef }>
|
|
56
|
+
<Popover
|
|
57
|
+
{ ...bindPopover( popupState ) }
|
|
58
|
+
anchorEl={ anchorRef.current }
|
|
59
|
+
anchorOrigin={ { vertical: 'bottom', horizontal: 'right' } }
|
|
60
|
+
transformOrigin={ { vertical: 'top', horizontal: 'right' } }
|
|
61
|
+
>
|
|
62
|
+
<Stack direction="row" alignItems="center" pl={ 1.5 } pr={ 0.5 } py={ 1.5 }>
|
|
63
|
+
<BrushIcon fontSize="tiny" sx={ { mr: 0.5 } } />
|
|
64
|
+
<Typography variant="subtitle2">{ __( 'Create variable', 'elementor' ) }</Typography>
|
|
65
|
+
<CloseButton
|
|
66
|
+
slotProps={ { icon: { fontSize: 'small' } } }
|
|
67
|
+
sx={ { ml: 'auto' } }
|
|
68
|
+
onClick={ closePopover }
|
|
69
|
+
/>
|
|
70
|
+
</Stack>
|
|
71
|
+
|
|
72
|
+
<Divider />
|
|
73
|
+
|
|
74
|
+
<Stack p={ 1.5 } gap={ 1.5 }>
|
|
75
|
+
<Grid container gap={ 0.75 } alignItems="center">
|
|
76
|
+
<Grid item xs={ 12 }>
|
|
77
|
+
<FormLabel size="small">{ __( 'Name', 'elementor' ) }</FormLabel>
|
|
78
|
+
</Grid>
|
|
79
|
+
<Grid item xs={ 12 }>
|
|
80
|
+
<TextField
|
|
81
|
+
size="tiny"
|
|
82
|
+
fullWidth
|
|
83
|
+
value={ label }
|
|
84
|
+
onChange={ ( e: React.ChangeEvent< HTMLInputElement > ) => setLabel( e.target.value ) }
|
|
85
|
+
/>
|
|
86
|
+
</Grid>
|
|
87
|
+
</Grid>
|
|
88
|
+
|
|
89
|
+
<Grid container gap={ 0.75 } alignItems="center">
|
|
90
|
+
<Grid item xs={ 12 }>
|
|
91
|
+
<FormLabel size="small">{ __( 'Value', 'elementor' ) }</FormLabel>
|
|
92
|
+
</Grid>
|
|
93
|
+
<Grid item xs={ 12 }>
|
|
94
|
+
<UnstableColorField
|
|
95
|
+
size="tiny"
|
|
96
|
+
fullWidth
|
|
97
|
+
value={ color }
|
|
98
|
+
onChange={ setColor }
|
|
99
|
+
slotProps={ {
|
|
100
|
+
colorPicker: {
|
|
101
|
+
anchorEl: anchorRef.current,
|
|
102
|
+
anchorOrigin: { vertical: 'top', horizontal: 'right' },
|
|
103
|
+
transformOrigin: { vertical: 'top', horizontal: -10 },
|
|
104
|
+
},
|
|
105
|
+
} }
|
|
106
|
+
/>
|
|
107
|
+
</Grid>
|
|
108
|
+
</Grid>
|
|
109
|
+
</Stack>
|
|
110
|
+
|
|
111
|
+
<CardActions>
|
|
112
|
+
<Button size="small" onClick={ closePopover } color="secondary" variant="text">
|
|
113
|
+
{ __( 'Cancel', 'elementor' ) }
|
|
114
|
+
</Button>
|
|
115
|
+
<Button size="small" variant="contained" disabled={ isInValidForm() } onClick={ handleCreate }>
|
|
116
|
+
{ __( 'Create', 'elementor' ) }
|
|
117
|
+
</Button>
|
|
118
|
+
</CardActions>
|
|
119
|
+
</Popover>
|
|
120
|
+
</Box>
|
|
121
|
+
);
|
|
122
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { useId } from 'react';
|
|
3
|
-
import { ColorFilterIcon, DetachIcon } from '@elementor/icons';
|
|
2
|
+
import { useId, useRef } from 'react';
|
|
3
|
+
import { ColorFilterIcon, DetachIcon, PlusIcon } from '@elementor/icons';
|
|
4
4
|
import {
|
|
5
5
|
bindPopover,
|
|
6
6
|
bindTrigger,
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
import { __ } from '@wordpress/i18n';
|
|
17
17
|
|
|
18
18
|
import { type Variable } from '../types';
|
|
19
|
+
import { ColorVariableCreation } from './color-variable-creation';
|
|
19
20
|
|
|
20
21
|
type Props = {
|
|
21
22
|
selectedVariable: Variable;
|
|
@@ -32,13 +33,20 @@ export const VariablesSelectionPopover = ( {
|
|
|
32
33
|
}: Props ) => {
|
|
33
34
|
const id = useId();
|
|
34
35
|
const popupState = usePopupState( { variant: 'popover', popupId: `elementor-variables-action-${ id }` } );
|
|
36
|
+
const creationPopupState = usePopupState( { variant: 'popover', popupId: `elementor-variables-creation-${ id }` } );
|
|
35
37
|
|
|
36
38
|
const closePopover = () => popupState.close();
|
|
37
39
|
|
|
40
|
+
const handleCreateButtonClick = ( event: React.MouseEvent ) => {
|
|
41
|
+
closePopover();
|
|
42
|
+
bindTrigger( creationPopupState ).onClick( event );
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const anchorRef = useRef< HTMLDivElement >( null );
|
|
38
46
|
const { label } = selectedVariable;
|
|
39
47
|
|
|
40
48
|
return (
|
|
41
|
-
<Box>
|
|
49
|
+
<Box ref={ anchorRef }>
|
|
42
50
|
<Tag
|
|
43
51
|
fullWidth
|
|
44
52
|
showActionsOnHover
|
|
@@ -57,28 +65,36 @@ export const VariablesSelectionPopover = ( {
|
|
|
57
65
|
</Box>
|
|
58
66
|
}
|
|
59
67
|
actions={
|
|
60
|
-
<IconButton size=
|
|
61
|
-
<DetachIcon fontSize=
|
|
68
|
+
<IconButton size="tiny" onClick={ unlinkVariable } aria-label={ __( 'Unlink', 'elementor' ) }>
|
|
69
|
+
<DetachIcon fontSize="tiny" />
|
|
62
70
|
</IconButton>
|
|
63
71
|
}
|
|
64
72
|
/>
|
|
65
73
|
<Popover
|
|
66
|
-
disableScrollLock
|
|
67
|
-
anchorOrigin={ { vertical: 'bottom', horizontal: 'center' } }
|
|
68
|
-
transformOrigin={ { vertical: 'top', horizontal: 'center' } }
|
|
69
74
|
{ ...bindPopover( popupState ) }
|
|
75
|
+
disableScrollLock
|
|
76
|
+
anchorEl={ anchorRef.current }
|
|
77
|
+
anchorOrigin={ { vertical: 'bottom', horizontal: 'right' } }
|
|
78
|
+
transformOrigin={ { vertical: 'top', horizontal: 'right' } }
|
|
70
79
|
>
|
|
71
80
|
<Stack direction="row" alignItems="center" pl={ 1.5 } pr={ 0.5 } py={ 1.5 }>
|
|
72
|
-
<ColorFilterIcon fontSize=
|
|
81
|
+
<ColorFilterIcon fontSize="tiny" sx={ { mr: 0.5 } } />
|
|
73
82
|
<Typography variant="subtitle2">{ __( 'Variables', 'elementor' ) }</Typography>
|
|
74
|
-
<
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
83
|
+
<Stack direction="row" sx={ { ml: 'auto' } }>
|
|
84
|
+
<IconButton
|
|
85
|
+
{ ...bindTrigger( creationPopupState ) }
|
|
86
|
+
size="tiny"
|
|
87
|
+
onClick={ handleCreateButtonClick }
|
|
88
|
+
>
|
|
89
|
+
<PlusIcon fontSize="tiny" />
|
|
90
|
+
</IconButton>
|
|
91
|
+
<CloseButton slotProps={ { icon: { fontSize: 'tiny' } } } onClick={ closePopover } />
|
|
92
|
+
</Stack>
|
|
79
93
|
</Stack>
|
|
80
|
-
{ children( { closePopover } ) }
|
|
94
|
+
{ children?.( { closePopover } ) }
|
|
81
95
|
</Popover>
|
|
96
|
+
|
|
97
|
+
<ColorVariableCreation popupState={ creationPopupState } />
|
|
82
98
|
</Box>
|
|
83
99
|
);
|
|
84
100
|
};
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { useMemo } from 'react';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import { type Variable } from '../types';
|
|
4
|
+
|
|
5
|
+
type VariableData = {
|
|
6
|
+
value: string;
|
|
7
|
+
label: string;
|
|
8
|
+
};
|
|
9
|
+
type Variables = Record< string, VariableData >;
|
|
4
10
|
|
|
5
11
|
type VariablesGroup = Record< string, Variables >;
|
|
6
12
|
|
|
@@ -9,7 +15,7 @@ export const usePropVariables = ( propTypeKey: string ) => {
|
|
|
9
15
|
};
|
|
10
16
|
|
|
11
17
|
export const useVariable = ( propTypeKey: string, key: string ) => {
|
|
12
|
-
if ( ! variables[ propTypeKey ][ key ] ) {
|
|
18
|
+
if ( ! variables[ propTypeKey ]?.[ key ] ) {
|
|
13
19
|
return null;
|
|
14
20
|
}
|
|
15
21
|
|
|
@@ -20,12 +26,32 @@ export const useVariable = ( propTypeKey: string, key: string ) => {
|
|
|
20
26
|
};
|
|
21
27
|
|
|
22
28
|
const normalizeVariables = ( propTypeKey: string ) => {
|
|
23
|
-
return Object.entries( variables[ propTypeKey ] ).map( ( [ key, { label, value } ] ) => ( {
|
|
29
|
+
return Object.entries( variables[ propTypeKey ] || {} ).map( ( [ key, { label, value } ] ) => ( {
|
|
24
30
|
key,
|
|
25
31
|
label,
|
|
26
32
|
value,
|
|
27
33
|
} ) );
|
|
28
34
|
};
|
|
29
35
|
|
|
36
|
+
export const createVariable = ( propTypeKey: string, variable: VariableData ) => {
|
|
37
|
+
const id = generateId( 'e-gv', Object.keys( variables[ propTypeKey ] ).length );
|
|
38
|
+
|
|
39
|
+
const newVariable: Variable = {
|
|
40
|
+
value: variable.value,
|
|
41
|
+
label: variable.label,
|
|
42
|
+
key: propTypeKey,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
variables[ propTypeKey ][ id ] = newVariable || {};
|
|
46
|
+
|
|
47
|
+
return id;
|
|
48
|
+
};
|
|
49
|
+
|
|
30
50
|
// @ts-expect-error the temporary solution to get the list of variables from the server
|
|
31
|
-
const variables: VariablesGroup = window?.ElementorV4Variables;
|
|
51
|
+
const variables: VariablesGroup = window?.ElementorV4Variables || {};
|
|
52
|
+
|
|
53
|
+
const generateId = ( prefix: string, variablesCount: number ) => {
|
|
54
|
+
const randomHex = Math.random().toString( 16 ).slice( 2, 9 );
|
|
55
|
+
|
|
56
|
+
return `${ prefix }${ randomHex }${ variablesCount }`;
|
|
57
|
+
};
|