@elementor/editor-variables 4.2.0-875 → 4.2.0-877

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elementor/editor-variables",
3
- "version": "4.2.0-875",
3
+ "version": "4.2.0-877",
4
4
  "private": false,
5
5
  "author": "Elementor Team",
6
6
  "homepage": "https://elementor.com/",
@@ -39,22 +39,22 @@
39
39
  "dev": "tsup --config=../../tsup.dev.ts"
40
40
  },
41
41
  "dependencies": {
42
- "@elementor/editor": "4.2.0-875",
43
- "@elementor/editor-canvas": "4.2.0-875",
44
- "@elementor/editor-controls": "4.2.0-875",
45
- "@elementor/editor-current-user": "4.2.0-875",
46
- "@elementor/editor-mcp": "4.2.0-875",
47
- "@elementor/editor-panels": "4.2.0-875",
48
- "@elementor/editor-props": "4.2.0-875",
49
- "@elementor/editor-ui": "4.2.0-875",
50
- "@elementor/editor-v1-adapters": "4.2.0-875",
51
- "@elementor/menus": "4.2.0-875",
52
- "@elementor/http-client": "4.2.0-875",
42
+ "@elementor/editor": "4.2.0-877",
43
+ "@elementor/editor-canvas": "4.2.0-877",
44
+ "@elementor/editor-controls": "4.2.0-877",
45
+ "@elementor/editor-current-user": "4.2.0-877",
46
+ "@elementor/editor-mcp": "4.2.0-877",
47
+ "@elementor/editor-panels": "4.2.0-877",
48
+ "@elementor/editor-props": "4.2.0-877",
49
+ "@elementor/editor-ui": "4.2.0-877",
50
+ "@elementor/editor-v1-adapters": "4.2.0-877",
51
+ "@elementor/menus": "4.2.0-877",
52
+ "@elementor/http-client": "4.2.0-877",
53
53
  "@elementor/icons": "~1.75.1",
54
- "@elementor/events": "4.2.0-875",
55
- "@elementor/schema": "4.2.0-875",
54
+ "@elementor/events": "4.2.0-877",
55
+ "@elementor/schema": "4.2.0-877",
56
56
  "@elementor/ui": "1.37.5",
57
- "@elementor/utils": "4.2.0-875",
57
+ "@elementor/utils": "4.2.0-877",
58
58
  "@wordpress/i18n": "^5.13.0"
59
59
  },
60
60
  "peerDependencies": {
@@ -1,30 +1,78 @@
1
1
  import { type MCPRegistryEntry } from '@elementor/editor-mcp';
2
2
  import { z } from '@elementor/schema';
3
+ import { isProActive } from '@elementor/utils';
3
4
 
4
5
  import { service } from '../service';
5
6
  import { validateLabel } from '../utils/validations';
7
+ import { generateVariablesPrompt, MANAGE_VARIABLES_GUIDE_URI } from './variable-tool-prompt';
6
8
  import { GLOBAL_VARIABLES_URI } from './variables-resource';
7
9
 
10
+ const VARIABLE_TYPES = {
11
+ COLOR: 'global-color-variable',
12
+ FONT: 'global-font-variable',
13
+ SIZE: 'global-size-variable',
14
+ CUSTOM_SIZE: 'global-custom-size-variable',
15
+ } as const;
16
+
17
+ const LENGTH_UNIT_PATTERN = /^(auto|\d+(\.\d+)?(px|rem|em|vh|vw|%|ch|s|ms))$/i;
18
+ const COLOR_PATTERN = /^(#[0-9a-f]{3,8}|rgba?\(|hsl)/i;
19
+
20
+ function validateValueForType( type: string, value: string ): string | null {
21
+ if ( type === VARIABLE_TYPES.FONT && LENGTH_UNIT_PATTERN.test( value.trim() ) ) {
22
+ return `Font variable value must be a font family name (e.g. "Roboto"), not a size value like "${ value }". Use "global-size-variable" or "global-custom-size-variable" for spacing/size values.`;
23
+ }
24
+
25
+ if ( type === VARIABLE_TYPES.COLOR && ! COLOR_PATTERN.test( value.trim() ) ) {
26
+ return `Color variable value should be a CSS color (e.g. "#FF0000"), got "${ value }".`;
27
+ }
28
+
29
+ if ( type === VARIABLE_TYPES.SIZE && ! LENGTH_UNIT_PATTERN.test( value.trim() ) ) {
30
+ return `Size variable value should include a CSS unit (e.g. "16px") or be "auto", got "${ value }".`;
31
+ }
32
+
33
+ return null;
34
+ }
35
+
8
36
  export const initManageVariableTool = ( reg: MCPRegistryEntry ) => {
9
- const { addTool } = reg;
37
+ const { addTool, resource } = reg;
38
+
39
+ resource(
40
+ 'manage-global-variable-guide',
41
+ MANAGE_VARIABLES_GUIDE_URI,
42
+ {
43
+ title: 'Manage Global Variable Guide',
44
+ description: 'Detailed guide for using the manage-global-variable tool',
45
+ mimeType: 'text/plain',
46
+ },
47
+ async ( uri: URL ) => ( {
48
+ contents: [ { uri: uri.href, mimeType: 'text/plain', text: generateVariablesPrompt() } ],
49
+ } )
50
+ );
51
+
10
52
  addTool( {
11
53
  name: 'manage-global-variable',
54
+ description: 'Manage V4 global variables (color, font, size). Read the guide resource before use.',
12
55
  schema: {
13
56
  action: z.enum( [ 'create', 'update', 'delete' ] ).describe( 'Operation to perform' ),
14
57
  id: z
15
58
  .string()
16
59
  .optional()
17
- .describe( 'Variable id (required for update/delete). Get from list-global-variables.' ),
60
+ .describe( 'Variable id required for update/delete. Get from the global-variables resource.' ),
18
61
  type: z
19
62
  .string()
20
63
  .optional()
21
- .describe( 'Variable type: "global-color-variable" or "global-font-variable" (required for create)' ),
22
- label: z.string().optional().describe( 'Variable label (required for create/update)' ),
64
+ .describe(
65
+ 'Variable type — required for create. One of: "global-color-variable", "global-font-variable", "global-size-variable", "global-custom-size-variable" (size types require Elementor Pro). NEVER store px/rem values in a font variable.'
66
+ ),
67
+ label: z
68
+ .string()
69
+ .optional()
70
+ .describe( 'Variable label (lowercase, dash-separated) — required for create/update.' ),
23
71
  value: z
24
72
  .string()
25
73
  .optional()
26
74
  .describe(
27
- 'The variable value (required for create/update). Provide a plain CSS value matching the variable type (font: family name; color: CSS color; size: value with unit). Never JSON.'
75
+ 'Plain CSS value required for create/update. Color: hex/rgba/hsl. Font: family name only, never px/rem. Size: value with unit e.g. "16px", or "auto" (Pro). Do NOT pass JSON.'
28
76
  ),
29
77
  },
30
78
  outputSchema: {
@@ -32,28 +80,22 @@ export const initManageVariableTool = ( reg: MCPRegistryEntry ) => {
32
80
  message: z.string().optional().describe( 'Error details if status is error' ),
33
81
  },
34
82
  requiredResources: [
83
+ { uri: MANAGE_VARIABLES_GUIDE_URI, description: 'Full guide for variable types, naming rules, and usage' },
35
84
  {
36
85
  uri: GLOBAL_VARIABLES_URI,
37
- description: 'Global variables',
86
+ description: 'Current global variables — check before creating to avoid duplicates',
38
87
  },
39
88
  ],
40
- description: `Create, update, or delete V4 global variables (distinct from legacy "globals").
41
- - Values: any valid CSS value, inserted as-is (1:1 with \`--css-var: VALUE\`). Do NOT pass JSON or legacy-globals object structures.
42
- - Names: lowercase, dash-separated (e.g. "Headline Primary" → "headline-primary").
43
- - Update: when renaming, keep the existing value; when updating value, keep the exact label.
44
- - Delete: destructive — confirm with user first.`,
89
+ isDestructive: true,
45
90
  handler: async ( params ) => {
46
91
  const operations = getServiceActions( service );
47
92
  const op = operations[ params.action ];
48
93
  if ( op ) {
49
94
  await op( params );
50
- return {
51
- status: 'ok',
52
- };
95
+ return { status: 'ok' };
53
96
  }
54
97
  throw new Error( `Unknown action ${ params.action }` );
55
98
  },
56
- isDestructive: true, // Because delete is destructive
57
99
  } );
58
100
  };
59
101
 
@@ -67,10 +109,17 @@ function getServiceActions( svc: typeof service ) {
67
109
  if ( ! type || ! label || ! value ) {
68
110
  throw new Error( 'Create requires type, label, and value' );
69
111
  }
112
+ if ( ( type === VARIABLE_TYPES.SIZE || type === VARIABLE_TYPES.CUSTOM_SIZE ) && ! isProActive() ) {
113
+ throw new Error( 'Creating size variables requires Elementor Pro.' );
114
+ }
70
115
  const labelError = validateLabel( label );
71
116
  if ( labelError ) {
72
117
  throw new Error( labelError );
73
118
  }
119
+ const valueError = validateValueForType( type, value );
120
+ if ( valueError ) {
121
+ throw new Error( valueError );
122
+ }
74
123
  return svc.create( { type, label, value } );
75
124
  },
76
125
  update( { id, label, value }: Opts< { id: string; label: string; value: string } > ) {
@@ -81,6 +130,13 @@ function getServiceActions( svc: typeof service ) {
81
130
  if ( labelError ) {
82
131
  throw new Error( labelError );
83
132
  }
133
+ const existingVariable = svc.variables()[ id ];
134
+ if ( existingVariable ) {
135
+ const valueError = validateValueForType( existingVariable.type, value );
136
+ if ( valueError ) {
137
+ throw new Error( valueError );
138
+ }
139
+ }
84
140
  return svc.update( id, { label, value } );
85
141
  },
86
142
  delete( { id }: Opts< { id: string } > ) {
@@ -0,0 +1,85 @@
1
+ import { toolPrompts } from '@elementor/editor-mcp';
2
+ import { isProActive } from '@elementor/utils';
3
+
4
+ export const MANAGE_VARIABLES_GUIDE_URI = 'elementor://variables/tools/manage-global-variable-guide';
5
+
6
+ export const generateVariablesPrompt = () => {
7
+ const prompt = toolPrompts( 'manage-global-variable' );
8
+ const proIsActive = isProActive();
9
+
10
+ const sizeVariableSection = proIsActive
11
+ ? `- **global-size-variable** — A simple CSS length with a unit (Elementor Pro). Use this for fixed spacing, font sizes, or layout values. Example: \`16px\`, \`1.5rem\`, \`2em\`, \`10vh\`
12
+ - **global-custom-size-variable** — Any CSS size expression that goes beyond a simple number + unit (Elementor Pro). Use this when the value is a CSS function, a keyword, or a combination of units that \`global-size-variable\` cannot represent. Example: \`auto\`, \`clamp(1rem, 2vw, 2rem)\`, \`calc(100% - 32px)\`, \`min(50vw, 600px)\`, \`300ms\`, \`2ch\`. When in doubt: if the value contains a function call or a keyword, use \`global-custom-size-variable\`.`
13
+ : `- ~~global-size-variable~~ — requires Elementor Pro (not available on this site)
14
+ - ~~global-custom-size-variable~~ — requires Elementor Pro (not available on this site)`;
15
+
16
+ prompt.description( `
17
+ # Purpose
18
+ Create, update, or delete V4 global CSS variables. These are distinct from legacy v3 globals and map 1:1 to \`--css-var: VALUE\`.
19
+
20
+ # Available Types
21
+ - **global-color-variable** — CSS color value. Example: \`#FF0000\`, \`rgba(255,0,0,1)\`, \`hsl(0,100%,50%)\`
22
+ - **global-font-variable** — Font family name ONLY — NOT a size or px value. Example: \`Roboto\`, \`Open Sans\`. NEVER pass px/rem here.
23
+ ${ sizeVariableSection }
24
+
25
+ # Naming Rules
26
+ - Labels must be **lowercase**, using only letters (a-z), numbers, digits (0-9), dashes (-), or underscores (_)
27
+ - No spaces, no special characters
28
+ - Example: "Headline Primary" → \`headline-primary\`
29
+ - Labels must be unique — always check [elementor://global-variables] first
30
+
31
+ # Value Rules
32
+ - Provide a **plain CSS value** only — do NOT pass JSON, legacy-globals object structures, or variable references
33
+ - Values are inserted as-is: \`--css-var: <value>\`
34
+ - NEVER store a px/rem value inside a \`global-font-variable\` — use \`global-size-variable\` (Pro) instead
35
+
36
+ # Operations
37
+ - **create** — requires \`type\`, \`label\`, \`value\`. Label must be unique.
38
+ - **update** — requires \`id\`, \`label\`, \`value\`. Get \`id\` from [elementor://global-variables]. When renaming: keep existing value. When changing value: keep exact existing label.
39
+ - **delete** — requires \`id\`. DESTRUCTIVE — always confirm with user before executing.
40
+ ` );
41
+
42
+ prompt.parameter( 'action', '"create", "update", or "delete".' );
43
+ prompt.parameter( 'type', 'Variable type. Required for create. See Available Types above.' );
44
+ prompt.parameter( 'label', 'Variable name (lowercase, dash-separated). Required for create/update.' );
45
+ prompt.parameter(
46
+ 'value',
47
+ 'Plain CSS value matching the variable type. Required for create/update. Do NOT pass JSON.'
48
+ );
49
+ prompt.parameter( 'id', 'Variable ID. Required for update/delete. Obtain from [elementor://global-variables].' );
50
+
51
+ prompt.example( `
52
+ Create a brand color:
53
+ { "action": "create", "type": "global-color-variable", "label": "brand-primary", "value": "#1A73E8" }
54
+
55
+ Create a heading font:
56
+ { "action": "create", "type": "global-font-variable", "label": "font-heading", "value": "Playfair Display" }
57
+
58
+ Create a simple spacing size:
59
+ { "action": "create", "type": "global-size-variable", "label": "spacing-md", "value": "16px" }
60
+
61
+ Create a fluid/responsive size using a CSS function (use global-custom-size-variable, NOT global-size-variable):
62
+ { "action": "create", "type": "global-custom-size-variable", "label": "spacing-fluid", "value": "clamp(1rem, 2vw, 2rem)" }
63
+
64
+ Create a size that is a keyword:
65
+ { "action": "create", "type": "global-custom-size-variable", "label": "width-auto", "value": "auto" }
66
+
67
+ Create a size using calc():
68
+ { "action": "create", "type": "global-custom-size-variable", "label": "sidebar-width", "value": "calc(100% - 32px)" }
69
+
70
+ Update a variable's value (keep exact label):
71
+ { "action": "update", "id": "abc123", "label": "brand-primary", "value": "#0D47A1" }
72
+
73
+ Rename a variable (keep existing value):
74
+ { "action": "update", "id": "abc123", "label": "brand-secondary", "value": "#1A73E8" }
75
+
76
+ Delete a variable:
77
+ { "action": "delete", "id": "abc123" }
78
+ ` );
79
+
80
+ prompt.instruction(
81
+ 'Always read [elementor://global-variables] before creating to check existing variables and avoid duplicate labels.'
82
+ );
83
+
84
+ return prompt.prompt();
85
+ };