@elementor/editor-variables 0.9.0 → 0.11.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 +28 -0
- package/dist/index.js +210 -28
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +210 -28
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -4
- package/src/api.ts +33 -0
- package/src/components/color-variable-creation.tsx +4 -4
- package/src/components/variables-selection-popover.tsx +13 -8
- package/src/hooks/use-prop-variables.ts +15 -19
- package/src/init.ts +3 -1
- package/src/service.ts +154 -0
- package/src/storage.ts +74 -0
|
@@ -42,14 +42,14 @@ export const ColorVariableCreation = ( { popupState }: { popupState: PopupState
|
|
|
42
42
|
};
|
|
43
43
|
|
|
44
44
|
const handleCreate = () => {
|
|
45
|
-
|
|
45
|
+
createVariable( {
|
|
46
46
|
value: color,
|
|
47
47
|
label,
|
|
48
48
|
type: colorVariablePropTypeUtil.key,
|
|
49
|
+
} ).then( ( key ) => {
|
|
50
|
+
setVariable( key );
|
|
51
|
+
closePopover();
|
|
49
52
|
} );
|
|
50
|
-
|
|
51
|
-
setVariable( key );
|
|
52
|
-
closePopover();
|
|
53
53
|
};
|
|
54
54
|
|
|
55
55
|
const isInValidForm = () => {
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
} from '@elementor/ui';
|
|
16
16
|
import { __ } from '@wordpress/i18n';
|
|
17
17
|
|
|
18
|
+
import { colorVariablePropTypeUtil } from '../prop-types/color-variable-prop-type';
|
|
18
19
|
import { type Variable } from '../types';
|
|
19
20
|
import { ColorVariableCreation } from './color-variable-creation';
|
|
20
21
|
|
|
@@ -45,6 +46,8 @@ export const VariablesSelectionPopover = ( {
|
|
|
45
46
|
const anchorRef = useRef< HTMLDivElement >( null );
|
|
46
47
|
const { label } = selectedVariable;
|
|
47
48
|
|
|
49
|
+
const colorCreationEnabled = colorVariablePropTypeUtil.key === selectedVariable.type;
|
|
50
|
+
|
|
48
51
|
return (
|
|
49
52
|
<Box ref={ anchorRef }>
|
|
50
53
|
<Tag
|
|
@@ -81,20 +84,22 @@ export const VariablesSelectionPopover = ( {
|
|
|
81
84
|
<ColorFilterIcon fontSize="tiny" sx={ { mr: 0.5 } } />
|
|
82
85
|
<Typography variant="subtitle2">{ __( 'Variables', 'elementor' ) }</Typography>
|
|
83
86
|
<Stack direction="row" sx={ { ml: 'auto' } }>
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
{ colorCreationEnabled && (
|
|
88
|
+
<IconButton
|
|
89
|
+
{ ...bindTrigger( creationPopupState ) }
|
|
90
|
+
size="tiny"
|
|
91
|
+
onClick={ handleCreateButtonClick }
|
|
92
|
+
>
|
|
93
|
+
<PlusIcon fontSize="tiny" />
|
|
94
|
+
</IconButton>
|
|
95
|
+
) }
|
|
91
96
|
<CloseButton slotProps={ { icon: { fontSize: 'tiny' } } } onClick={ closePopover } />
|
|
92
97
|
</Stack>
|
|
93
98
|
</Stack>
|
|
94
99
|
{ children?.( { closePopover } ) }
|
|
95
100
|
</Popover>
|
|
96
101
|
|
|
97
|
-
<ColorVariableCreation popupState={ creationPopupState } />
|
|
102
|
+
{ colorCreationEnabled && <ColorVariableCreation popupState={ creationPopupState } /> }
|
|
98
103
|
</Box>
|
|
99
104
|
);
|
|
100
105
|
};
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import { useMemo } from 'react';
|
|
2
2
|
import { type PropKey } from '@elementor/editor-props';
|
|
3
3
|
|
|
4
|
+
import { service } from '../service';
|
|
5
|
+
import { type TVariable } from '../storage';
|
|
4
6
|
import { styleVariablesRepository } from '../style-variables-repository';
|
|
5
|
-
import { type Variable
|
|
7
|
+
import { type Variable } from '../types';
|
|
6
8
|
|
|
7
9
|
export const usePropVariables = ( propKey: PropKey ) => {
|
|
8
10
|
return useMemo( () => normalizeVariables( propKey ), [ propKey ] );
|
|
9
11
|
};
|
|
10
12
|
|
|
11
13
|
export const useVariable = ( key: string ) => {
|
|
14
|
+
const variables = service.variables();
|
|
15
|
+
|
|
12
16
|
if ( ! variables?.[ key ] ) {
|
|
13
17
|
return null;
|
|
14
18
|
}
|
|
@@ -20,6 +24,10 @@ export const useVariable = ( key: string ) => {
|
|
|
20
24
|
};
|
|
21
25
|
|
|
22
26
|
const normalizeVariables = ( propKey: string ) => {
|
|
27
|
+
const variables = service.variables();
|
|
28
|
+
|
|
29
|
+
styleVariablesRepository.update( variables );
|
|
30
|
+
|
|
23
31
|
return Object.entries( variables )
|
|
24
32
|
.filter( ( [ , { type } ] ) => type === propKey )
|
|
25
33
|
.map( ( [ key, { label, value } ] ) => ( {
|
|
@@ -29,23 +37,11 @@ const normalizeVariables = ( propKey: string ) => {
|
|
|
29
37
|
} ) );
|
|
30
38
|
};
|
|
31
39
|
|
|
32
|
-
export const createVariable = (
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
[ id ]: variable,
|
|
40
|
+
export const createVariable = ( newVariable: Variable ): Promise< string > => {
|
|
41
|
+
return service.create( newVariable ).then( ( { id, variable }: { id: string; variable: TVariable } ) => {
|
|
42
|
+
styleVariablesRepository.update( {
|
|
43
|
+
[ id ]: variable,
|
|
44
|
+
} );
|
|
45
|
+
return id;
|
|
39
46
|
} );
|
|
40
|
-
|
|
41
|
-
return id;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
// @ts-expect-error the temporary solution to get the list of variables from the server
|
|
45
|
-
const variables: Variables = window?.ElementorV4Variables || {};
|
|
46
|
-
|
|
47
|
-
const generateId = ( prefix = 'e-gv' ) => {
|
|
48
|
-
const randomHex = Math.random().toString( 16 ).slice( 2, 9 );
|
|
49
|
-
|
|
50
|
-
return `${ prefix }${ randomHex }`;
|
|
51
47
|
};
|
package/src/init.ts
CHANGED
|
@@ -3,12 +3,14 @@ import { injectIntoTop } from '@elementor/editor';
|
|
|
3
3
|
import { initColorVariables } from './init-color-variables';
|
|
4
4
|
import { initFontVariables } from './init-font-variables';
|
|
5
5
|
import { StyleVariablesRenderer } from './renderers/style-variables-renderer';
|
|
6
|
+
import { service as variablesService } from './service';
|
|
6
7
|
|
|
7
8
|
export function init() {
|
|
8
9
|
initColorVariables();
|
|
9
|
-
|
|
10
10
|
initFontVariables();
|
|
11
11
|
|
|
12
|
+
variablesService.init();
|
|
13
|
+
|
|
12
14
|
injectIntoTop( {
|
|
13
15
|
id: 'canvas-style-variables-render',
|
|
14
16
|
component: StyleVariablesRenderer,
|
package/src/service.ts
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { apiClient } from './api';
|
|
2
|
+
import { OP_RW, Storage, type TVariable, type TVariablesList } from './storage';
|
|
3
|
+
|
|
4
|
+
const storage = new Storage();
|
|
5
|
+
|
|
6
|
+
export const service = {
|
|
7
|
+
variables: (): TVariablesList => {
|
|
8
|
+
return storage.load();
|
|
9
|
+
},
|
|
10
|
+
|
|
11
|
+
init: () => {
|
|
12
|
+
service.load();
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
load: () => {
|
|
16
|
+
return apiClient
|
|
17
|
+
.list()
|
|
18
|
+
.then( ( response ) => {
|
|
19
|
+
const { success, data: payload } = response.data;
|
|
20
|
+
|
|
21
|
+
if ( ! success ) {
|
|
22
|
+
throw new Error( 'Unexpected response from server' );
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return payload;
|
|
26
|
+
} )
|
|
27
|
+
.then( ( data ) => {
|
|
28
|
+
const { variables, watermark } = data;
|
|
29
|
+
|
|
30
|
+
storage.fill( variables, watermark );
|
|
31
|
+
|
|
32
|
+
return variables;
|
|
33
|
+
} );
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
create: ( { type, label, value }: TVariable ) => {
|
|
37
|
+
return apiClient
|
|
38
|
+
.create( type, label, value )
|
|
39
|
+
.then( ( response ) => {
|
|
40
|
+
const { success, data: payload } = response.data;
|
|
41
|
+
|
|
42
|
+
if ( ! success ) {
|
|
43
|
+
throw new Error( 'Unexpected response from server' );
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return payload;
|
|
47
|
+
} )
|
|
48
|
+
.then( ( data ) => {
|
|
49
|
+
const { variable, watermark } = data;
|
|
50
|
+
|
|
51
|
+
handleWatermark( OP_RW, watermark );
|
|
52
|
+
|
|
53
|
+
const { id: variableId, ...createdVariable } = variable;
|
|
54
|
+
|
|
55
|
+
storage.add( variableId, createdVariable );
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
id: variableId,
|
|
59
|
+
variable: createdVariable,
|
|
60
|
+
};
|
|
61
|
+
} );
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
update: ( id: string, { label, value }: TVariable ) => {
|
|
65
|
+
return apiClient
|
|
66
|
+
.update( id, label, value )
|
|
67
|
+
.then( ( response ) => {
|
|
68
|
+
const { success, data: payload } = response.data;
|
|
69
|
+
|
|
70
|
+
if ( ! success ) {
|
|
71
|
+
throw new Error( 'Unexpected response from server' );
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return payload;
|
|
75
|
+
} )
|
|
76
|
+
.then( ( data ) => {
|
|
77
|
+
const { variable, watermark } = data;
|
|
78
|
+
|
|
79
|
+
handleWatermark( OP_RW, watermark );
|
|
80
|
+
|
|
81
|
+
const { id: variableId, ...updatedVariable } = variable;
|
|
82
|
+
|
|
83
|
+
storage.update( variableId, updatedVariable );
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
id: variableId,
|
|
87
|
+
variable: updatedVariable,
|
|
88
|
+
};
|
|
89
|
+
} );
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
delete: ( id: string ) => {
|
|
93
|
+
return apiClient
|
|
94
|
+
.delete( id )
|
|
95
|
+
.then( ( response ) => {
|
|
96
|
+
const { success, data: payload } = response.data;
|
|
97
|
+
|
|
98
|
+
if ( ! success ) {
|
|
99
|
+
throw new Error( 'Unexpected response from server' );
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return payload;
|
|
103
|
+
} )
|
|
104
|
+
.then( ( data ) => {
|
|
105
|
+
const { variable, watermark } = data;
|
|
106
|
+
|
|
107
|
+
handleWatermark( OP_RW, watermark );
|
|
108
|
+
|
|
109
|
+
const { id: variableId, ...deletedVariable } = variable;
|
|
110
|
+
|
|
111
|
+
storage.update( variableId, deletedVariable );
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
id: variableId,
|
|
115
|
+
variable: deletedVariable,
|
|
116
|
+
};
|
|
117
|
+
} );
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
restore: ( id: string ) => {
|
|
121
|
+
return apiClient
|
|
122
|
+
.restore( id )
|
|
123
|
+
.then( ( response ) => {
|
|
124
|
+
const { success, data: payload } = response.data;
|
|
125
|
+
|
|
126
|
+
if ( ! success ) {
|
|
127
|
+
throw new Error( 'Unexpected response from server' );
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return payload;
|
|
131
|
+
} )
|
|
132
|
+
.then( ( data ) => {
|
|
133
|
+
const { variable, watermark } = data;
|
|
134
|
+
|
|
135
|
+
handleWatermark( OP_RW, watermark );
|
|
136
|
+
|
|
137
|
+
const { id: variableId, ...restoredVariable } = variable;
|
|
138
|
+
|
|
139
|
+
storage.update( variableId, restoredVariable );
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
id: variableId,
|
|
143
|
+
variable: restoredVariable,
|
|
144
|
+
};
|
|
145
|
+
} );
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const handleWatermark = ( operation: string, newWatermark: number ) => {
|
|
150
|
+
if ( storage.watermarkDiff( operation, newWatermark ) ) {
|
|
151
|
+
setTimeout( () => service.load(), 500 );
|
|
152
|
+
}
|
|
153
|
+
storage.watermark( newWatermark );
|
|
154
|
+
};
|
package/src/storage.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export type TVariable = {
|
|
2
|
+
type: string;
|
|
3
|
+
label: string;
|
|
4
|
+
value: string;
|
|
5
|
+
deleted?: boolean;
|
|
6
|
+
deleted_at?: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export type TVariablesList = Record< string, TVariable >;
|
|
10
|
+
|
|
11
|
+
const STORAGE_KEY = 'elementor-global-variables';
|
|
12
|
+
const STORAGE_WATERMARK_KEY = 'elementor-global-variables-watermark';
|
|
13
|
+
|
|
14
|
+
export const OP_RW = 'RW';
|
|
15
|
+
const OP_RO = 'RO';
|
|
16
|
+
|
|
17
|
+
export class Storage {
|
|
18
|
+
state: {
|
|
19
|
+
watermark: number;
|
|
20
|
+
variables: TVariablesList;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
constructor() {
|
|
24
|
+
this.state = {
|
|
25
|
+
watermark: -1,
|
|
26
|
+
variables: {},
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
load() {
|
|
31
|
+
this.state.watermark = parseInt( localStorage.getItem( STORAGE_WATERMARK_KEY ) || '-1' );
|
|
32
|
+
this.state.variables = JSON.parse( localStorage.getItem( STORAGE_KEY ) || '{}' ) as TVariablesList;
|
|
33
|
+
return this.state.variables;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
fill( variables: TVariablesList, watermark: number ) {
|
|
37
|
+
this.state.watermark = watermark;
|
|
38
|
+
this.state.variables = variables;
|
|
39
|
+
|
|
40
|
+
localStorage.setItem( STORAGE_WATERMARK_KEY, this.state.watermark.toString() );
|
|
41
|
+
localStorage.setItem( STORAGE_KEY, JSON.stringify( this.state.variables ) );
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
add( id: string, variable: TVariable ) {
|
|
45
|
+
this.load();
|
|
46
|
+
this.state.variables[ id ] = variable;
|
|
47
|
+
localStorage.setItem( STORAGE_KEY, JSON.stringify( this.state.variables ) );
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
update( id: string, variable: TVariable ) {
|
|
51
|
+
this.load();
|
|
52
|
+
this.state.variables[ id ] = variable;
|
|
53
|
+
localStorage.setItem( STORAGE_KEY, JSON.stringify( this.state.variables ) );
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
watermark( watermark: number ) {
|
|
57
|
+
this.state.watermark = watermark;
|
|
58
|
+
localStorage.setItem( STORAGE_WATERMARK_KEY, this.state.watermark.toString() );
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
watermarkDiff( operation: string, newWatermark: number ) {
|
|
62
|
+
const diff = newWatermark - this.state.watermark;
|
|
63
|
+
|
|
64
|
+
if ( OP_RW === operation ) {
|
|
65
|
+
return 1 !== diff;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if ( OP_RO === operation ) {
|
|
69
|
+
return 0 !== diff;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}
|