@elementor/editor-variables 0.15.0 → 0.18.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.
Files changed (36) hide show
  1. package/CHANGELOG.md +88 -0
  2. package/dist/index.js +894 -486
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.mjs +892 -511
  5. package/dist/index.mjs.map +1 -1
  6. package/package.json +9 -9
  7. package/src/components/color-variable-creation.tsx +37 -58
  8. package/src/components/color-variable-edit.tsx +110 -86
  9. package/src/components/color-variables-selection.tsx +32 -34
  10. package/src/components/fields/color-field.tsx +54 -0
  11. package/src/components/fields/font-field.tsx +85 -0
  12. package/src/components/fields/label-field.tsx +54 -0
  13. package/src/components/font-variable-creation.tsx +39 -78
  14. package/src/components/font-variable-edit.tsx +108 -114
  15. package/src/components/font-variables-selection.tsx +32 -34
  16. package/src/components/ui/delete-confirmation-dialog.tsx +52 -0
  17. package/src/components/ui/deleted-variable-alert.tsx +47 -0
  18. package/src/components/ui/menu-item-content.tsx +2 -5
  19. package/src/components/ui/tags/assigned-tag.tsx +45 -0
  20. package/src/components/ui/tags/deleted-tag.tsx +37 -0
  21. package/src/components/ui/variable/assigned-variable.tsx +70 -0
  22. package/src/components/ui/variable/deleted-variable.tsx +76 -0
  23. package/src/controls/color-variable-control.tsx +21 -48
  24. package/src/controls/font-variable-control.tsx +20 -43
  25. package/src/create-style-variables-repository.ts +44 -5
  26. package/src/hooks/use-prop-variables.ts +6 -0
  27. package/src/init-color-variables.ts +3 -48
  28. package/src/renderers/style-variables-renderer.tsx +10 -4
  29. package/src/repeater-injections.ts +35 -0
  30. package/src/service.ts +23 -2
  31. package/src/sync/enqueue-font.ts +7 -0
  32. package/src/sync/types.ts +5 -0
  33. package/src/transformers/variable-transformer.ts +21 -3
  34. package/src/types.ts +1 -1
  35. package/src/utils/validations.ts +42 -0
  36. package/src/components/ui/variable-tag.tsx +0 -43
package/src/service.ts CHANGED
@@ -1,3 +1,6 @@
1
+ import { type AxiosResponse } from '@elementor/http-client';
2
+ import { __ } from '@wordpress/i18n';
3
+
1
4
  import { apiClient } from './api';
2
5
  import { OP_RW, Storage, type TVariablesList } from './storage';
3
6
  import { styleVariablesRepository } from './style-variables-repository';
@@ -44,7 +47,8 @@ export const service = {
44
47
  const { success, data: payload } = response.data;
45
48
 
46
49
  if ( ! success ) {
47
- throw new Error( 'Unexpected response from server' );
50
+ const errorMessage = payload?.message || __( 'Unexpected response from server', 'elementor' );
51
+ throw new Error( errorMessage );
48
52
  }
49
53
 
50
54
  return payload;
@@ -66,6 +70,10 @@ export const service = {
66
70
  id: variableId,
67
71
  variable: createdVariable,
68
72
  };
73
+ } )
74
+ .catch( ( error ) => {
75
+ const message = getErrorMessage( error.response );
76
+ throw message ? new Error( message ) : error;
69
77
  } );
70
78
  },
71
79
 
@@ -76,7 +84,8 @@ export const service = {
76
84
  const { success, data: payload } = response.data;
77
85
 
78
86
  if ( ! success ) {
79
- throw new Error( 'Unexpected response from server' );
87
+ const errorMessage = payload?.message || __( 'Unexpected response from server', 'elementor' );
88
+ throw new Error( errorMessage );
80
89
  }
81
90
 
82
91
  return payload;
@@ -98,6 +107,10 @@ export const service = {
98
107
  id: variableId,
99
108
  variable: updatedVariable,
100
109
  };
110
+ } )
111
+ .catch( ( error ) => {
112
+ const message = getErrorMessage( error.response );
113
+ throw message ? new Error( message ) : error;
101
114
  } );
102
115
  },
103
116
 
@@ -172,3 +185,11 @@ const handleWatermark = ( operation: string, newWatermark: number ) => {
172
185
  }
173
186
  storage.watermark( newWatermark );
174
187
  };
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,7 @@
1
+ import { type CanvasExtendedWindow, type EnqueueFont } from './types';
2
+
3
+ export const enqueueFont: EnqueueFont = ( fontFamily, context = 'preview' ) => {
4
+ const extendedWindow = window as unknown as CanvasExtendedWindow;
5
+
6
+ return extendedWindow.elementor?.helpers?.enqueueFont?.( fontFamily, context ) ?? null;
7
+ };
package/src/sync/types.ts CHANGED
@@ -1,5 +1,10 @@
1
+ export type EnqueueFont = ( fontFamily: string, context?: 'preview' | 'editor' ) => void;
2
+
1
3
  export type CanvasExtendedWindow = Window & {
2
4
  elementor?: {
3
5
  $preview?: [ HTMLIFrameElement ];
6
+ helpers?: {
7
+ enqueueFont?: EnqueueFont;
8
+ };
4
9
  };
5
10
  };
@@ -1,9 +1,27 @@
1
1
  import { createTransformer } from '@elementor/editor-canvas';
2
2
 
3
- export const variableTransformer = createTransformer( ( value: string ) => {
4
- if ( ! value.trim() ) {
3
+ import { service } from '../service';
4
+
5
+ export const variableTransformer = createTransformer( ( id: string ) => {
6
+ const variables = service.variables();
7
+
8
+ let name = id;
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() ) {
5
19
  return null;
6
20
  }
7
21
 
8
- return `var(--${ value })`;
22
+ if ( ! fallbackValue.trim() ) {
23
+ return `var(--${ name })`;
24
+ }
25
+
26
+ return `var(--${ name }, ${ fallbackValue })`;
9
27
  } );
package/src/types.ts CHANGED
@@ -10,7 +10,7 @@ export type Variable = {
10
10
  deleted_at?: string;
11
11
  };
12
12
 
13
- export type StyleVariables = Record< string, string >;
13
+ export type StyleVariables = Record< string, Variable >;
14
14
 
15
15
  export type ExtendedVirtualizedItem = VirtualizedItem< 'item', string > & {
16
16
  icon: React.ReactNode;
@@ -0,0 +1,42 @@
1
+ import { __ } from '@wordpress/i18n';
2
+
3
+ export const VARIABLE_LABEL_MAX_LENGTH = 50;
4
+
5
+ export const validateLabel = ( name: string ): string => {
6
+ if ( ! name.trim() ) {
7
+ return __( 'Give your variable a name.', 'elementor' );
8
+ }
9
+
10
+ const allowedChars = /^[a-zA-Z0-9_-]+$/;
11
+ if ( ! allowedChars.test( name ) ) {
12
+ return __( 'Use letters, numbers, dashes (-), or underscores (_) for the name.', 'elementor' );
13
+ }
14
+
15
+ const hasAlphanumeric = /[a-zA-Z0-9]/;
16
+ if ( ! hasAlphanumeric.test( name ) ) {
17
+ return __( 'Names have to include at least one non-special character.', 'elementor' );
18
+ }
19
+
20
+ if ( VARIABLE_LABEL_MAX_LENGTH < name.length ) {
21
+ return __( 'Keep names up to 50 characters.', 'elementor' );
22
+ }
23
+
24
+ return '';
25
+ };
26
+
27
+ export const labelHint = ( name: string ): string => {
28
+ const hintThreshold = VARIABLE_LABEL_MAX_LENGTH * 0.8 - 1;
29
+ if ( hintThreshold < name.length ) {
30
+ return __( 'Keep names up to 50 characters.', 'elementor' );
31
+ }
32
+
33
+ return '';
34
+ };
35
+
36
+ export const validateValue = ( value: string ): string => {
37
+ if ( ! value.trim() ) {
38
+ return __( 'Add a value to complete your variable.', 'elementor' );
39
+ }
40
+
41
+ return '';
42
+ };
@@ -1,43 +0,0 @@
1
- import * as React from 'react';
2
- import { DetachIcon } from '@elementor/icons';
3
- import { Box, IconButton, Stack, Typography, UnstableTag as Tag, type UnstableTagProps } from '@elementor/ui';
4
- import { __ } from '@wordpress/i18n';
5
-
6
- export const SIZE = 'tiny';
7
-
8
- interface VariableTagProps extends UnstableTagProps {
9
- onUnlink?: () => void;
10
- }
11
-
12
- export const VariableTag = ( { startIcon, label, onUnlink, ...props }: VariableTagProps ) => {
13
- const actions = [];
14
-
15
- if ( onUnlink ) {
16
- actions.push(
17
- <IconButton key="unlink" size={ SIZE } onClick={ onUnlink } aria-label={ __( 'Unlink', 'elementor' ) }>
18
- <DetachIcon fontSize={ SIZE } />
19
- </IconButton>
20
- );
21
- }
22
-
23
- return (
24
- <Tag
25
- fullWidth
26
- showActionsOnHover
27
- startIcon={
28
- <Stack gap={ 0.5 } direction="row" alignItems="center">
29
- { startIcon }
30
- </Stack>
31
- }
32
- label={
33
- <Box sx={ { display: 'inline-grid', minWidth: 0 } }>
34
- <Typography sx={ { lineHeight: 1.34 } } variant="caption" noWrap>
35
- { label }
36
- </Typography>
37
- </Box>
38
- }
39
- actions={ actions }
40
- { ...props }
41
- />
42
- );
43
- };