@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.
- package/CHANGELOG.md +0 -28
- package/dist/index.d.mts +19 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.js +1282 -1026
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1262 -990
- package/dist/index.mjs.map +1 -1
- package/package.json +16 -14
- package/src/api.ts +18 -2
- package/src/components/fields/color-field.tsx +3 -3
- package/src/components/fields/font-field.tsx +21 -10
- package/src/components/fields/label-field.tsx +31 -5
- package/src/components/ui/edit-confirmation-dialog.tsx +75 -0
- package/src/components/ui/missing-variable-alert.tsx +39 -0
- package/src/components/ui/no-variables.tsx +59 -26
- package/src/components/ui/tags/missing-tag.tsx +25 -0
- package/src/components/ui/variable/assigned-variable.tsx +11 -14
- package/src/components/ui/variable/deleted-variable.tsx +102 -50
- package/src/components/ui/variable/missing-variable.tsx +44 -0
- package/src/components/{color-variable-creation.tsx → variable-creation.tsx} +51 -22
- package/src/components/variable-edit.tsx +221 -0
- package/src/components/variable-restore.tsx +117 -0
- package/src/components/variable-selection-popover.tsx +91 -92
- package/src/components/variables-manager/variables-manager-panel.tsx +115 -0
- package/src/components/{font-variables-selection.tsx → variables-selection.tsx} +38 -17
- package/src/context/variable-selection-popover.context.tsx +19 -0
- package/src/context/variable-type-context.tsx +23 -0
- package/src/controls/variable-control.tsx +26 -0
- package/src/hooks/use-initial-value.ts +22 -0
- package/src/hooks/use-permissions.ts +15 -0
- package/src/hooks/use-prop-variable-action.tsx +53 -0
- package/src/hooks/use-prop-variables.ts +2 -2
- package/src/index.ts +1 -0
- package/src/init.ts +33 -4
- package/src/register-variable-types.tsx +29 -0
- package/src/repeater-injections.ts +5 -1
- package/src/service.ts +2 -19
- package/src/transformers/inheritance-transformer.tsx +30 -0
- package/src/transformers/utils/resolve-css-variable.ts +24 -0
- package/src/transformers/variable-transformer.ts +3 -16
- package/src/utils/tracking.ts +39 -0
- package/src/utils/validations.ts +40 -6
- package/src/variables-registry/create-variable-type-registry.ts +77 -0
- package/src/variables-registry/variable-type-registry.ts +3 -0
- package/src/components/color-variable-edit.tsx +0 -157
- package/src/components/color-variables-selection.tsx +0 -128
- package/src/components/font-variable-creation.tsx +0 -106
- package/src/components/font-variable-edit.tsx +0 -157
- package/src/components/variable-selection-popover.context.ts +0 -7
- package/src/controls/color-variable-control.tsx +0 -39
- package/src/controls/font-variable-control.tsx +0 -37
- package/src/hooks/use-prop-color-variable-action.tsx +0 -25
- package/src/hooks/use-prop-font-variable-action.tsx +0 -25
- package/src/init-color-variables.ts +0 -27
- package/src/init-font-variables.ts +0 -24
- package/src/utils.ts +0 -20
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { useBoundProp } from '@elementor/editor-controls';
|
|
2
|
+
|
|
3
|
+
import { hasVariableType } from '../variables-registry/variable-type-registry';
|
|
4
|
+
import { useVariable } from './use-prop-variables';
|
|
5
|
+
|
|
6
|
+
type PropValue = {
|
|
7
|
+
$$type: string;
|
|
8
|
+
value: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const useInitialValue = () => {
|
|
12
|
+
const { value: initial }: { value: PropValue } = useBoundProp();
|
|
13
|
+
|
|
14
|
+
const hasAssignedVariable = hasVariableType( initial?.$$type ) && Boolean( initial?.value );
|
|
15
|
+
const variable = useVariable( hasAssignedVariable ? initial.value : '' );
|
|
16
|
+
|
|
17
|
+
if ( hasAssignedVariable ) {
|
|
18
|
+
return variable ? variable.value : '';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return initial?.value ?? '';
|
|
22
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useCurrentUserCapabilities } from '@elementor/editor-current-user';
|
|
2
|
+
|
|
3
|
+
export const usePermissions = () => {
|
|
4
|
+
const { canUser } = useCurrentUserCapabilities();
|
|
5
|
+
|
|
6
|
+
return {
|
|
7
|
+
canAssign: () => canUser( 'edit_posts' ),
|
|
8
|
+
canUnlink: () => canUser( 'edit_posts' ),
|
|
9
|
+
canAdd: () => canUser( 'manage_options' ),
|
|
10
|
+
canDelete: () => canUser( 'manage_options' ),
|
|
11
|
+
canEdit: () => canUser( 'manage_options' ),
|
|
12
|
+
canRestore: () => canUser( 'manage_options' ),
|
|
13
|
+
canManageSettings: () => canUser( 'manage_options' ),
|
|
14
|
+
};
|
|
15
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type PopoverActionProps, useBoundProp } from '@elementor/editor-editing-panel';
|
|
3
|
+
import { type PropType } from '@elementor/editor-props';
|
|
4
|
+
import { ColorFilterIcon } from '@elementor/icons';
|
|
5
|
+
import { __ } from '@wordpress/i18n';
|
|
6
|
+
|
|
7
|
+
import { VariableSelectionPopover } from '../components/variable-selection-popover';
|
|
8
|
+
import { trackVariableEvent } from '../utils/tracking';
|
|
9
|
+
import { getVariableType } from '../variables-registry/variable-type-registry';
|
|
10
|
+
|
|
11
|
+
export const usePropVariableAction = (): PopoverActionProps => {
|
|
12
|
+
const { propType, path } = useBoundProp();
|
|
13
|
+
const variable = resolveVariableFromPropType( propType );
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
visible: Boolean( variable ),
|
|
17
|
+
icon: ColorFilterIcon,
|
|
18
|
+
title: __( 'Variables', 'elementor' ),
|
|
19
|
+
content: ( { close: closePopover } ) => {
|
|
20
|
+
if ( ! variable ) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
trackOpenVariablePopover( path, variable.variableType );
|
|
25
|
+
|
|
26
|
+
return <VariableSelectionPopover closePopover={ closePopover } propTypeKey={ variable.propTypeUtil.key } />;
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const resolveVariableFromPropType = ( propType: PropType ) => {
|
|
32
|
+
if ( propType.kind !== 'union' ) {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
for ( const key of Object.keys( propType.prop_types ) ) {
|
|
37
|
+
const variable = getVariableType( key );
|
|
38
|
+
|
|
39
|
+
if ( variable ) {
|
|
40
|
+
return variable;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return undefined;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const trackOpenVariablePopover = ( path: string[], variableType: string ) => {
|
|
48
|
+
trackVariableEvent( {
|
|
49
|
+
varType: variableType,
|
|
50
|
+
controlPath: path.join( '.' ),
|
|
51
|
+
action: 'open',
|
|
52
|
+
} );
|
|
53
|
+
};
|
|
@@ -67,8 +67,8 @@ export const deleteVariable = ( deleteId: string ) => {
|
|
|
67
67
|
} );
|
|
68
68
|
};
|
|
69
69
|
|
|
70
|
-
export const restoreVariable = ( restoreId: string ) => {
|
|
71
|
-
return service.restore( restoreId ).then( ( { id }: { id: string } ) => {
|
|
70
|
+
export const restoreVariable = ( restoreId: string, label?: string, value?: string ) => {
|
|
71
|
+
return service.restore( restoreId, label, value ).then( ( { id }: { id: string } ) => {
|
|
72
72
|
return id;
|
|
73
73
|
} );
|
|
74
74
|
};
|
package/src/index.ts
CHANGED
package/src/init.ts
CHANGED
|
@@ -1,13 +1,32 @@
|
|
|
1
1
|
import { injectIntoTop } from '@elementor/editor';
|
|
2
|
+
import { controlActionsMenu, registerControlReplacement } from '@elementor/editor-editing-panel';
|
|
3
|
+
import { __registerPanel as registerPanel } from '@elementor/editor-panels';
|
|
4
|
+
import type { PropValue } from '@elementor/editor-props';
|
|
2
5
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
6
|
+
import { panel } from './components/variables-manager/variables-manager-panel';
|
|
7
|
+
import { VariableControl } from './controls/variable-control';
|
|
8
|
+
import { usePropVariableAction } from './hooks/use-prop-variable-action';
|
|
9
|
+
import { registerVariableTypes } from './register-variable-types';
|
|
5
10
|
import { StyleVariablesRenderer } from './renderers/style-variables-renderer';
|
|
11
|
+
import { registerRepeaterInjections } from './repeater-injections';
|
|
6
12
|
import { service as variablesService } from './service';
|
|
13
|
+
import { hasVariableType } from './variables-registry/variable-type-registry';
|
|
14
|
+
|
|
15
|
+
const { registerPopoverAction } = controlActionsMenu;
|
|
7
16
|
|
|
8
17
|
export function init() {
|
|
9
|
-
|
|
10
|
-
|
|
18
|
+
registerVariableTypes();
|
|
19
|
+
registerRepeaterInjections();
|
|
20
|
+
|
|
21
|
+
registerControlReplacement( {
|
|
22
|
+
component: VariableControl,
|
|
23
|
+
condition: ( { value } ) => hasAssignedVariable( value ),
|
|
24
|
+
} );
|
|
25
|
+
|
|
26
|
+
registerPopoverAction( {
|
|
27
|
+
id: 'variables',
|
|
28
|
+
useProps: usePropVariableAction,
|
|
29
|
+
} );
|
|
11
30
|
|
|
12
31
|
variablesService.init();
|
|
13
32
|
|
|
@@ -15,4 +34,14 @@ export function init() {
|
|
|
15
34
|
id: 'canvas-style-variables-render',
|
|
16
35
|
component: StyleVariablesRenderer,
|
|
17
36
|
} );
|
|
37
|
+
|
|
38
|
+
registerPanel( panel );
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function hasAssignedVariable( propValue: PropValue ) {
|
|
42
|
+
if ( propValue && typeof propValue === 'object' && '$$type' in propValue ) {
|
|
43
|
+
return hasVariableType( propValue.$$type );
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return false;
|
|
18
47
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { colorPropTypeUtil, stringPropTypeUtil } from '@elementor/editor-props';
|
|
3
|
+
import { BrushIcon, TextIcon } from '@elementor/icons';
|
|
4
|
+
|
|
5
|
+
import { ColorField } from './components/fields/color-field';
|
|
6
|
+
import { FontField } from './components/fields/font-field';
|
|
7
|
+
import { ColorIndicator } from './components/ui/color-indicator';
|
|
8
|
+
import { colorVariablePropTypeUtil } from './prop-types/color-variable-prop-type';
|
|
9
|
+
import { fontVariablePropTypeUtil } from './prop-types/font-variable-prop-type';
|
|
10
|
+
import { registerVariableType } from './variables-registry/variable-type-registry';
|
|
11
|
+
|
|
12
|
+
export function registerVariableTypes() {
|
|
13
|
+
registerVariableType( {
|
|
14
|
+
valueField: ColorField,
|
|
15
|
+
icon: BrushIcon,
|
|
16
|
+
propTypeUtil: colorVariablePropTypeUtil,
|
|
17
|
+
fallbackPropTypeUtil: colorPropTypeUtil,
|
|
18
|
+
variableType: 'color',
|
|
19
|
+
startIcon: ( { value } ) => <ColorIndicator size="inherit" component="span" value={ value } />,
|
|
20
|
+
} );
|
|
21
|
+
|
|
22
|
+
registerVariableType( {
|
|
23
|
+
valueField: FontField,
|
|
24
|
+
icon: TextIcon,
|
|
25
|
+
propTypeUtil: fontVariablePropTypeUtil,
|
|
26
|
+
fallbackPropTypeUtil: stringPropTypeUtil,
|
|
27
|
+
variableType: 'font',
|
|
28
|
+
} );
|
|
29
|
+
}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
BackgroundRepeaterLabel,
|
|
7
7
|
BoxShadowRepeaterColorIndicator,
|
|
8
8
|
} from './components/variables-repeater-item-slot';
|
|
9
|
-
import {
|
|
9
|
+
import { colorVariablePropTypeUtil } from './prop-types/color-variable-prop-type';
|
|
10
10
|
|
|
11
11
|
export function registerRepeaterInjections() {
|
|
12
12
|
injectIntoRepeaterItemIcon( {
|
|
@@ -33,3 +33,7 @@ export function registerRepeaterInjections() {
|
|
|
33
33
|
},
|
|
34
34
|
} );
|
|
35
35
|
}
|
|
36
|
+
|
|
37
|
+
const hasAssignedColorVariable = ( propValue: PropValue ): boolean => {
|
|
38
|
+
return !! colorVariablePropTypeUtil.isValid( propValue );
|
|
39
|
+
};
|
package/src/service.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { type AxiosResponse } from '@elementor/http-client';
|
|
2
1
|
import { __ } from '@wordpress/i18n';
|
|
3
2
|
|
|
4
3
|
import { apiClient } from './api';
|
|
@@ -70,10 +69,6 @@ export const service = {
|
|
|
70
69
|
id: variableId,
|
|
71
70
|
variable: createdVariable,
|
|
72
71
|
};
|
|
73
|
-
} )
|
|
74
|
-
.catch( ( error ) => {
|
|
75
|
-
const message = getErrorMessage( error.response );
|
|
76
|
-
throw message ? new Error( message ) : error;
|
|
77
72
|
} );
|
|
78
73
|
},
|
|
79
74
|
|
|
@@ -107,10 +102,6 @@ export const service = {
|
|
|
107
102
|
id: variableId,
|
|
108
103
|
variable: updatedVariable,
|
|
109
104
|
};
|
|
110
|
-
} )
|
|
111
|
-
.catch( ( error ) => {
|
|
112
|
-
const message = getErrorMessage( error.response );
|
|
113
|
-
throw message ? new Error( message ) : error;
|
|
114
105
|
} );
|
|
115
106
|
},
|
|
116
107
|
|
|
@@ -146,9 +137,9 @@ export const service = {
|
|
|
146
137
|
} );
|
|
147
138
|
},
|
|
148
139
|
|
|
149
|
-
restore: ( id: string ) => {
|
|
140
|
+
restore: ( id: string, label?: string, value?: string ) => {
|
|
150
141
|
return apiClient
|
|
151
|
-
.restore( id )
|
|
142
|
+
.restore( id, label, value )
|
|
152
143
|
.then( ( response ) => {
|
|
153
144
|
const { success, data: payload } = response.data;
|
|
154
145
|
|
|
@@ -185,11 +176,3 @@ const handleWatermark = ( operation: string, newWatermark: number ) => {
|
|
|
185
176
|
}
|
|
186
177
|
storage.watermark( newWatermark );
|
|
187
178
|
};
|
|
188
|
-
|
|
189
|
-
const getErrorMessage = ( response: AxiosResponse ) => {
|
|
190
|
-
if ( response?.data?.code === 'duplicated_label' ) {
|
|
191
|
-
return __( 'This variable name already exists. Please choose a unique name.', 'elementor' );
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
return __( 'There was a glitch. Try saving your variable again.', 'elementor' );
|
|
195
|
-
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { createTransformer } from '@elementor/editor-canvas';
|
|
3
|
+
import { Stack, Typography } from '@elementor/ui';
|
|
4
|
+
import { __ } from '@wordpress/i18n';
|
|
5
|
+
|
|
6
|
+
import { ColorIndicator } from '../components/ui/color-indicator';
|
|
7
|
+
import { colorVariablePropTypeUtil } from '../prop-types/color-variable-prop-type';
|
|
8
|
+
import { service } from '../service';
|
|
9
|
+
import { resolveCssVariable } from './utils/resolve-css-variable';
|
|
10
|
+
|
|
11
|
+
export const inheritanceTransformer = createTransformer( ( id: string ) => {
|
|
12
|
+
const variables = service.variables();
|
|
13
|
+
const variable = variables[ id ];
|
|
14
|
+
|
|
15
|
+
if ( ! variable ) {
|
|
16
|
+
return <span>{ __( 'Missing variable', 'elementor' ) }</span>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const showColorIndicator = variable.type === colorVariablePropTypeUtil.key;
|
|
20
|
+
const css = resolveCssVariable( id, variable );
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<Stack direction="row" spacing={ 0.5 } sx={ { paddingInline: '1px' } } alignItems="center">
|
|
24
|
+
{ showColorIndicator && <ColorIndicator size="inherit" value={ variable.value } /> }
|
|
25
|
+
<Typography variant="caption" overflow="hidden" whiteSpace="nowrap" textOverflow="ellipsis">
|
|
26
|
+
{ css }
|
|
27
|
+
</Typography>
|
|
28
|
+
</Stack>
|
|
29
|
+
);
|
|
30
|
+
} );
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type TVariable } from '../../storage';
|
|
2
|
+
|
|
3
|
+
export const resolveCssVariable = ( id: string, variable: TVariable ) => {
|
|
4
|
+
let name = id;
|
|
5
|
+
let fallbackValue = '';
|
|
6
|
+
|
|
7
|
+
if ( variable ) {
|
|
8
|
+
fallbackValue = variable.value;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if ( variable && ! variable.deleted ) {
|
|
12
|
+
name = variable.label;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if ( ! name.trim() ) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if ( ! fallbackValue.trim() ) {
|
|
20
|
+
return `var(--${ name })`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return `var(--${ name }, ${ fallbackValue })`;
|
|
24
|
+
};
|
|
@@ -1,27 +1,14 @@
|
|
|
1
1
|
import { createTransformer } from '@elementor/editor-canvas';
|
|
2
2
|
|
|
3
3
|
import { service } from '../service';
|
|
4
|
+
import { resolveCssVariable } from './utils/resolve-css-variable';
|
|
4
5
|
|
|
5
6
|
export const variableTransformer = createTransformer( ( id: string ) => {
|
|
6
7
|
const variables = service.variables();
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
let fallbackValue = '';
|
|
10
|
-
|
|
11
|
-
if ( variables[ id ] ) {
|
|
12
|
-
fallbackValue = variables[ id ].value;
|
|
13
|
-
if ( ! variables[ id ]?.deleted ) {
|
|
14
|
-
name = variables[ id ].label;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
if ( ! name.trim() ) {
|
|
9
|
+
if ( ! variables[ id ] ) {
|
|
19
10
|
return null;
|
|
20
11
|
}
|
|
21
12
|
|
|
22
|
-
|
|
23
|
-
return `var(--${ name })`;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return `var(--${ name }, ${ fallbackValue })`;
|
|
13
|
+
return resolveCssVariable( id, variables[ id ] );
|
|
27
14
|
} );
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
type VariableEventData = {
|
|
2
|
+
varType: string;
|
|
3
|
+
controlPath: string;
|
|
4
|
+
action: 'open' | 'add' | 'connect' | 'save';
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const trackVariableEvent = ( { varType, controlPath, action }: VariableEventData ) => {
|
|
8
|
+
const extendedWindow = window as unknown as Window & {
|
|
9
|
+
elementorCommon?: {
|
|
10
|
+
eventsManager?: {
|
|
11
|
+
dispatchEvent: ( name: string, data: Record< string, string > ) => void;
|
|
12
|
+
config?: {
|
|
13
|
+
locations: Record< string, string >;
|
|
14
|
+
secondaryLocations: Record< string, string >;
|
|
15
|
+
names: {
|
|
16
|
+
variables?: Record< string, string >;
|
|
17
|
+
};
|
|
18
|
+
triggers: Record< string, string >;
|
|
19
|
+
elements?: Record< string, string >;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const config = extendedWindow?.elementorCommon?.eventsManager?.config;
|
|
26
|
+
if ( ! config?.names?.variables?.[ action ] ) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const name = config.names.variables[ action ];
|
|
31
|
+
extendedWindow.elementorCommon?.eventsManager?.dispatchEvent( name, {
|
|
32
|
+
location: config.locations.variables,
|
|
33
|
+
secondaryLocation: config.secondaryLocations.variablesPopover,
|
|
34
|
+
trigger: config.triggers.click,
|
|
35
|
+
var_type: varType,
|
|
36
|
+
control_path: controlPath,
|
|
37
|
+
action_type: name,
|
|
38
|
+
} );
|
|
39
|
+
};
|
package/src/utils/validations.ts
CHANGED
|
@@ -1,24 +1,58 @@
|
|
|
1
1
|
import { __ } from '@wordpress/i18n';
|
|
2
2
|
|
|
3
|
+
export const ERROR_MESSAGES = {
|
|
4
|
+
MISSING_VARIABLE_NAME: __( 'Give your variable a name.', 'elementor' ),
|
|
5
|
+
MISSING_VARIABLE_VALUE: __( 'Add a value to complete your variable.', 'elementor' ),
|
|
6
|
+
INVALID_CHARACTERS: __( 'Use letters, numbers, dashes (-), or underscores (_) for the name.', 'elementor' ),
|
|
7
|
+
NO_NON_SPECIAL_CHARACTER: __( 'Names have to include at least one non-special character.', 'elementor' ),
|
|
8
|
+
VARIABLE_LABEL_MAX_LENGTH: __( 'Keep names up to 50 characters.', 'elementor' ),
|
|
9
|
+
DUPLICATED_LABEL: __( 'This variable name already exists. Please choose a unique name.', 'elementor' ),
|
|
10
|
+
UNEXPECTED_ERROR: __( 'There was a glitch. Try saving your variable again.', 'elementor' ),
|
|
11
|
+
} as const;
|
|
12
|
+
|
|
3
13
|
export const VARIABLE_LABEL_MAX_LENGTH = 50;
|
|
4
14
|
|
|
15
|
+
type ErrorResponse = {
|
|
16
|
+
response?: {
|
|
17
|
+
data?: {
|
|
18
|
+
code?: string;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type MappedError = {
|
|
24
|
+
field: string;
|
|
25
|
+
message: string;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const mapServerError = ( error: ErrorResponse ): MappedError | undefined => {
|
|
29
|
+
if ( error?.response?.data?.code === 'duplicated_label' ) {
|
|
30
|
+
return {
|
|
31
|
+
field: 'label',
|
|
32
|
+
message: ERROR_MESSAGES.DUPLICATED_LABEL,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return undefined;
|
|
37
|
+
};
|
|
38
|
+
|
|
5
39
|
export const validateLabel = ( name: string ): string => {
|
|
6
40
|
if ( ! name.trim() ) {
|
|
7
|
-
return
|
|
41
|
+
return ERROR_MESSAGES.MISSING_VARIABLE_NAME;
|
|
8
42
|
}
|
|
9
43
|
|
|
10
44
|
const allowedChars = /^[a-zA-Z0-9_-]+$/;
|
|
11
45
|
if ( ! allowedChars.test( name ) ) {
|
|
12
|
-
return
|
|
46
|
+
return ERROR_MESSAGES.INVALID_CHARACTERS;
|
|
13
47
|
}
|
|
14
48
|
|
|
15
49
|
const hasAlphanumeric = /[a-zA-Z0-9]/;
|
|
16
50
|
if ( ! hasAlphanumeric.test( name ) ) {
|
|
17
|
-
return
|
|
51
|
+
return ERROR_MESSAGES.NO_NON_SPECIAL_CHARACTER;
|
|
18
52
|
}
|
|
19
53
|
|
|
20
54
|
if ( VARIABLE_LABEL_MAX_LENGTH < name.length ) {
|
|
21
|
-
return
|
|
55
|
+
return ERROR_MESSAGES.VARIABLE_LABEL_MAX_LENGTH;
|
|
22
56
|
}
|
|
23
57
|
|
|
24
58
|
return '';
|
|
@@ -27,7 +61,7 @@ export const validateLabel = ( name: string ): string => {
|
|
|
27
61
|
export const labelHint = ( name: string ): string => {
|
|
28
62
|
const hintThreshold = VARIABLE_LABEL_MAX_LENGTH * 0.8 - 1;
|
|
29
63
|
if ( hintThreshold < name.length ) {
|
|
30
|
-
return
|
|
64
|
+
return ERROR_MESSAGES.VARIABLE_LABEL_MAX_LENGTH;
|
|
31
65
|
}
|
|
32
66
|
|
|
33
67
|
return '';
|
|
@@ -35,7 +69,7 @@ export const labelHint = ( name: string ): string => {
|
|
|
35
69
|
|
|
36
70
|
export const validateValue = ( value: string ): string => {
|
|
37
71
|
if ( ! value.trim() ) {
|
|
38
|
-
return
|
|
72
|
+
return ERROR_MESSAGES.MISSING_VARIABLE_VALUE;
|
|
39
73
|
}
|
|
40
74
|
|
|
41
75
|
return '';
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { type ForwardRefExoticComponent, type JSX, type RefAttributes } from 'react';
|
|
2
|
+
import { styleTransformersRegistry } from '@elementor/editor-canvas';
|
|
3
|
+
import { stylesInheritanceTransformersRegistry } from '@elementor/editor-editing-panel';
|
|
4
|
+
import { type createPropUtils, type PropTypeKey, type PropTypeUtil } from '@elementor/editor-props';
|
|
5
|
+
import { type SvgIconProps } from '@elementor/ui';
|
|
6
|
+
|
|
7
|
+
import { inheritanceTransformer } from '../transformers/inheritance-transformer';
|
|
8
|
+
import { variableTransformer } from '../transformers/variable-transformer';
|
|
9
|
+
|
|
10
|
+
type ValueFieldProps = {
|
|
11
|
+
value: string;
|
|
12
|
+
onChange: ( value: string ) => void;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type FallbackPropTypeUtil = ReturnType< typeof createPropUtils >;
|
|
16
|
+
|
|
17
|
+
type VariableTypeOptions = {
|
|
18
|
+
icon: ForwardRefExoticComponent< Omit< SvgIconProps, 'ref' > & RefAttributes< SVGSVGElement > >;
|
|
19
|
+
startIcon?: ( { value }: { value: string } ) => JSX.Element;
|
|
20
|
+
valueField: ( { value, onChange }: ValueFieldProps ) => JSX.Element;
|
|
21
|
+
variableType: string;
|
|
22
|
+
fallbackPropTypeUtil: FallbackPropTypeUtil;
|
|
23
|
+
propTypeUtil: PropTypeUtil< string, string >;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type VariableTypesMap = Record< string, VariableTypeOptions >;
|
|
27
|
+
|
|
28
|
+
export function createVariableTypeRegistry() {
|
|
29
|
+
const variableTypes: VariableTypesMap = {};
|
|
30
|
+
|
|
31
|
+
const registerVariableType = ( {
|
|
32
|
+
icon,
|
|
33
|
+
startIcon,
|
|
34
|
+
valueField,
|
|
35
|
+
propTypeUtil,
|
|
36
|
+
variableType,
|
|
37
|
+
fallbackPropTypeUtil,
|
|
38
|
+
}: VariableTypeOptions ) => {
|
|
39
|
+
if ( variableTypes[ propTypeUtil.key ] ) {
|
|
40
|
+
throw new Error( `Variable with key "${ propTypeUtil.key }" is already registered.` );
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
variableTypes[ propTypeUtil.key ] = {
|
|
44
|
+
icon,
|
|
45
|
+
startIcon,
|
|
46
|
+
valueField,
|
|
47
|
+
propTypeUtil,
|
|
48
|
+
variableType,
|
|
49
|
+
fallbackPropTypeUtil,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
registerTransformer( propTypeUtil.key );
|
|
53
|
+
registerInheritanceTransformer( propTypeUtil.key );
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const registerTransformer = ( key: PropTypeKey ) => {
|
|
57
|
+
styleTransformersRegistry.register( key, variableTransformer );
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const registerInheritanceTransformer = ( key: PropTypeKey ) => {
|
|
61
|
+
stylesInheritanceTransformersRegistry.register( key, inheritanceTransformer );
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const getVariableType = ( key: string ) => {
|
|
65
|
+
return variableTypes[ key ];
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const hasVariableType = ( key: string ) => {
|
|
69
|
+
return key in variableTypes;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
registerVariableType,
|
|
74
|
+
getVariableType,
|
|
75
|
+
hasVariableType,
|
|
76
|
+
};
|
|
77
|
+
}
|