PluginProbe
Elementor Website Builder – more than just a page builder / 4.3.2
Elementor Website Builder – more than just a page builder v4.3.2
4.3.2 4.3.1 4.3.0 4.3.0-beta3 4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 All 455 releases
elementor / assets / js / packages / editor-variables / editor-variables.js

editor-variables.js in Elementor Website Builder – more than just a page builder 4.3.2, at assets/js/packages/editor-variables/editor-variables.js

3,894 lines 147.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function(react, _elementor_editor_current_user, _elementor_editor_panels, _elementor_editor_ui, _elementor_icons, _elementor_ui, _wordpress_i18n, _elementor_events, _elementor_editor_canvas, _elementor_editor_props, _elementor_schema, _elementor_http_client, _elementor_editor_v1_adapters, _elementor_editor_controls, _elementor_utils, _elementor_editor, _elementor_editor_mcp, _elementor_menus) {
2
3 //#region \0rolldown/runtime.js
4 var __create = Object.create;
5 var __defProp$1 = Object.defineProperty;
6 var __name = (target, value) => __defProp$1(target, "name", {
7 value,
8 configurable: true
9 });
10 var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
11 var __getOwnPropNames = Object.getOwnPropertyNames;
12 var __getProtoOf = Object.getPrototypeOf;
13 var __hasOwnProp = Object.prototype.hasOwnProperty;
14 var __exportAll = (all, no_symbols) => {
15 let target = {};
16 for (var name in all) {
17 __defProp$1(target, name, {
18 get: all[name],
19 enumerable: true
20 });
21 }
22 if (!no_symbols) {
23 __defProp$1(target, Symbol.toStringTag, { value: "Module" });
24 }
25 return target;
26 };
27 var __copyProps = (to, from, except, desc) => {
28 if (from && typeof from === "object" || typeof from === "function") {
29 for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
30 key = keys[i];
31 if (!__hasOwnProp.call(to, key) && key !== except) {
32 __defProp$1(to, key, {
33 get: ((k) => from[k]).bind(null, key),
34 enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
35 });
36 }
37 }
38 }
39 return to;
40 };
41 var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp$1(target, "default", {
42 value: mod,
43 enumerable: true
44 }) : target, mod));
45
46 //#endregion
47 react = __toESM(react);
48
49 //#region packages/packages/core/editor-variables/src/utils/tracking.ts
50 var trackVariableEvent = ({ varType, controlPath, action, executedBy }) => {
51 const { dispatchEvent, config } = (0, _elementor_events.getMixpanel)();
52 if (!config?.names?.variables?.[action]) return;
53 const name = config.names.variables[action];
54 let eventData = {
55 var_type: varType,
56 action_type: name
57 };
58 if (executedBy) eventData.executed_by = executedBy;
59 const defaultLocationInfo = {
60 location: config?.locations?.variables || "",
61 secondaryLocation: config?.secondaryLocations?.variablesPopover || "",
62 trigger: config?.triggers?.click || ""
63 };
64 if (!executedBy || executedBy !== "mcp_tool") eventData = {
65 ...defaultLocationInfo,
66 ...eventData
67 };
68 if (controlPath) eventData.control_path = controlPath;
69 dispatchEvent?.(name, eventData);
70 };
71 var trackVariablesManagerEvent = ({ action, source, varType, controlPath }) => {
72 const { dispatchEvent, config } = (0, _elementor_events.getMixpanel)();
73 if (!config?.names?.variables?.[action]) return;
74 const name = config.names.variables[action];
75 const eventData = {
76 location: config?.locations?.variablesManager || "",
77 trigger: config?.triggers?.click || "",
78 action_type: name
79 };
80 if (source) eventData.source = source;
81 if (varType) eventData.var_type = varType;
82 if (controlPath) eventData.style_control_path = controlPath;
83 dispatchEvent?.(name, eventData);
84 };
85 var trackVariableSyncToV3 = ({ variableLabel, action }) => {
86 const { dispatchEvent, config } = (0, _elementor_events.getMixpanel)();
87 if (!config?.names?.variables?.variableSyncToV3) return;
88 const name = config.names.variables.variableSyncToV3;
89 const isSync = action === "sync";
90 dispatchEvent?.(name, {
91 interaction_type: "click",
92 target_type: variableLabel,
93 target_name: isSync ? "sync_to_v3" : "unsync_to_v3",
94 interaction_result: isSync ? "var_is_synced_to_V3" : "var_is_unsynced_from_V3",
95 target_location: "widget_panel",
96 location_l1: "var_manager",
97 interaction_description: isSync ? `user_synced_${variableLabel}_to_v3` : `user_unsync_${variableLabel}_from_v3`
98 });
99 };
100
101 //#endregion
102 //#region packages/packages/core/editor-variables/src/utils/validations.ts
103 var ERROR_MESSAGES = {
104 MISSING_VARIABLE_NAME: (0, _wordpress_i18n.__)("Give your variable a name.", "elementor"),
105 MISSING_VARIABLE_VALUE: (0, _wordpress_i18n.__)("Add a value to complete your variable.", "elementor"),
106 INVALID_CHARACTERS: (0, _wordpress_i18n.__)("Use letters, numbers, dashes (-), or underscores (_) for the name.", "elementor"),
107 NO_NON_SPECIAL_CHARACTER: (0, _wordpress_i18n.__)("Names have to include at least one non-special character.", "elementor"),
108 VARIABLE_LABEL_MAX_LENGTH: (0, _wordpress_i18n.__)("Keep names up to 50 characters.", "elementor"),
109 DUPLICATED_LABEL: (0, _wordpress_i18n.__)("This variable name already exists. Please choose a unique name.", "elementor"),
110 UNEXPECTED_ERROR: (0, _wordpress_i18n.__)("There was a glitch. Try saving your variable again.", "elementor"),
111 BATCH: {
112 DUPLICATED_LABELS: (count, name) => (0, _wordpress_i18n.sprintf)((0, _wordpress_i18n.__)("We found %1$d duplicated %2$s.", "elementor"), count, name),
113 UNEXPECTED_ERROR: (0, _wordpress_i18n.__)("There was a glitch.", "elementor"),
114 DUPLICATED_LABEL_ACTION: (0, _wordpress_i18n.__)("Take me there", "elementor"),
115 DUPLICATED_LABEL_ACTION_MESSAGE: (0, _wordpress_i18n.__)("Please rename the variables.", "elementor"),
116 UNEXPECTED_ERROR_ACTION_MESSAGE: (0, _wordpress_i18n.__)("Try saving your variables again.", "elementor")
117 }
118 };
119 var VARIABLE_LABEL_MAX_LENGTH = 50;
120 var mapServerError = (error) => {
121 if (error?.response?.data?.code === "duplicated_label") return {
122 field: "label",
123 message: ERROR_MESSAGES.DUPLICATED_LABEL
124 };
125 if (error?.response?.data?.code === "batch_duplicated_label") {
126 const errorData = error?.response?.data?.data ?? {};
127 const count = Object.keys(errorData).length;
128 const name = count === 1 ? "name" : "names";
129 const duplicatedIds = Object.keys(errorData);
130 return {
131 field: "label",
132 message: ERROR_MESSAGES.BATCH.DUPLICATED_LABELS(count, name),
133 severity: "error",
134 IconComponent: _elementor_icons.AlertTriangleFilledIcon,
135 action: {
136 label: ERROR_MESSAGES.BATCH.DUPLICATED_LABEL_ACTION,
137 message: ERROR_MESSAGES.BATCH.DUPLICATED_LABEL_ACTION_MESSAGE,
138 data: { duplicatedIds }
139 }
140 };
141 }
142 if (error?.response?.data?.code === "batch_operation_failed") return {
143 field: "label",
144 message: ERROR_MESSAGES.BATCH.UNEXPECTED_ERROR,
145 severity: "secondary",
146 IconComponent: _elementor_icons.InfoCircleFilledIcon,
147 action: { message: ERROR_MESSAGES.BATCH.UNEXPECTED_ERROR_ACTION_MESSAGE }
148 };
149 };
150 var validateLabel = (name, variables) => {
151 if (!name.trim()) return ERROR_MESSAGES.MISSING_VARIABLE_NAME;
152 if (!/^[a-zA-Z0-9_-]+$/.test(name)) return ERROR_MESSAGES.INVALID_CHARACTERS;
153 if (!/[a-zA-Z0-9]/.test(name)) return ERROR_MESSAGES.NO_NON_SPECIAL_CHARACTER;
154 if (50 < name.length) return ERROR_MESSAGES.VARIABLE_LABEL_MAX_LENGTH;
155 if (Object.values(variables ?? {}).some((variable) => variable.label === name)) return ERROR_MESSAGES.DUPLICATED_LABEL;
156 return "";
157 };
158 var labelHint = (name) => {
159 if (50 * .8 - 1 < name.length) return ERROR_MESSAGES.VARIABLE_LABEL_MAX_LENGTH;
160 return "";
161 };
162 var validateValue = (value) => {
163 if (!value.trim()) return ERROR_MESSAGES.MISSING_VARIABLE_VALUE;
164 return "";
165 };
166
167 //#endregion
168 //#region packages/packages/core/editor-variables/src/components/ui/color-indicator.tsx
169 var ColorIndicator = (0, _elementor_ui.styled)(_elementor_ui.UnstableColorIndicator)(({ theme }) => ({
170 borderRadius: `${theme.shape.borderRadius / 2}px`,
171 marginRight: theme.spacing(.25)
172 }));
173
174 //#endregion
175 //#region packages/packages/core/editor-variables/src/prop-types/color-variable-prop-type.ts
176 var colorVariablePropTypeUtil = (0, _elementor_editor_props.createPropUtils)("global-color-variable", _elementor_schema.z.string());
177
178 //#endregion
179 //#region packages/packages/core/editor-variables/src/api.ts
180 var apiClient = {
181 list: () => {
182 return (0, _elementor_http_client.httpService)().get("elementor/v1/variables/list");
183 },
184 create: (type, label, value) => {
185 return (0, _elementor_http_client.httpService)().post("elementor/v1/variables/create", {
186 type,
187 label,
188 value
189 });
190 },
191 update: (id, label, value, type) => {
192 return (0, _elementor_http_client.httpService)().put("elementor/v1/variables/update", {
193 id,
194 label,
195 value,
196 type
197 });
198 },
199 delete: (id) => {
200 return (0, _elementor_http_client.httpService)().post("elementor/v1/variables/delete", { id });
201 },
202 restore: (id, label, value, type) => {
203 const payload = { id };
204 if (label) payload.label = label;
205 if (value) payload.value = value;
206 if (type) payload.type = type;
207 return (0, _elementor_http_client.httpService)().post("elementor/v1/variables/restore", payload);
208 },
209 batch: (payload) => {
210 return (0, _elementor_http_client.httpService)().post("elementor/v1/variables/batch", payload);
211 }
212 };
213
214 //#endregion
215 //#region packages/packages/core/editor-variables/src/batch-operations.ts
216 var generateTempId = () => {
217 return `tmp-${Date.now().toString(36)}-${Math.random().toString(36).substring(2, 8)}`;
218 };
219 var isTempId = (id) => {
220 return id.startsWith("tmp-");
221 };
222 var buildOperationsArray = (originalVariables, currentVariables, deletedVariables) => {
223 const operations = [];
224 Object.entries(currentVariables).forEach(([id, variable]) => {
225 if (isTempId(id)) operations.push({
226 type: "create",
227 variable: {
228 ...variable,
229 id
230 }
231 });
232 else if (originalVariables[id]) {
233 const original = originalVariables[id];
234 const syncChanged = original.sync_to_v3 !== variable.sync_to_v3;
235 if (original.deleted && !variable.deleted) operations.push({
236 type: "restore",
237 id,
238 ...original.label !== variable.label && { label: variable.label },
239 ...original.value !== variable.value && { value: variable.value }
240 });
241 else if (!variable.deleted && (original.label !== variable.label || original.value !== variable.value || original.order !== variable.order || original.type !== variable.type || syncChanged)) operations.push({
242 type: "update",
243 id,
244 variable: {
245 ...original.label !== variable.label && { label: variable.label },
246 ...original.value !== variable.value && { value: variable.value },
247 ...original.order !== variable.order && { order: variable.order },
248 ...original.type !== variable.type && { type: variable.type },
249 ...syncChanged && { sync_to_v3: variable.sync_to_v3 }
250 }
251 });
252 }
253 });
254 deletedVariables.forEach((id) => {
255 operations.push({
256 type: "delete",
257 id
258 });
259 });
260 return operations.filter((op) => {
261 const id = op.id || op.variable?.id;
262 return id && !(isTempId(id) && currentVariables[id]?.deleted);
263 });
264 };
265
266 //#endregion
267 //#region packages/packages/core/editor-variables/src/storage.ts
268 var __defProp = Object.defineProperty;
269 var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, {
270 enumerable: true,
271 configurable: true,
272 writable: true,
273 value
274 }) : obj[key] = value;
275 var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
276 var STORAGE_KEY = "elementor-global-variables";
277 var STORAGE_WATERMARK_KEY = "elementor-global-variables-watermark";
278 var STORAGE_UPDATED_EVENT = "variables:updated";
279 var OP_RW = "RW";
280 var OP_RO = "RO";
281 var Storage = class {
282 constructor() {
283 __publicField(this, "state");
284 this.state = {
285 watermark: -1,
286 variables: {}
287 };
288 }
289 notifyChange() {
290 window.dispatchEvent(new Event(STORAGE_UPDATED_EVENT));
291 }
292 load() {
293 this.state.watermark = parseInt(localStorage.getItem(STORAGE_WATERMARK_KEY) || "-1");
294 this.state.variables = JSON.parse(localStorage.getItem(STORAGE_KEY) || "{}");
295 return this.state.variables;
296 }
297 fill(variables, watermark) {
298 this.state.variables = {};
299 if (variables && Object.keys(variables).length) this.state.variables = variables;
300 this.state.watermark = watermark;
301 localStorage.setItem(STORAGE_WATERMARK_KEY, this.state.watermark.toString());
302 localStorage.setItem(STORAGE_KEY, JSON.stringify(this.state.variables));
303 this.notifyChange();
304 }
305 add(id, variable) {
306 this.load();
307 this.state.variables[id] = variable;
308 localStorage.setItem(STORAGE_KEY, JSON.stringify(this.state.variables));
309 this.notifyChange();
310 }
311 update(id, variable) {
312 this.load();
313 this.state.variables[id] = variable;
314 localStorage.setItem(STORAGE_KEY, JSON.stringify(this.state.variables));
315 this.notifyChange();
316 }
317 watermark(watermark) {
318 this.state.watermark = watermark;
319 localStorage.setItem(STORAGE_WATERMARK_KEY, this.state.watermark.toString());
320 }
321 watermarkDiff(operation, newWatermark) {
322 const diff = newWatermark - this.state.watermark;
323 if ("RW" === operation) return 1 !== diff;
324 if (OP_RO === operation) return 0 !== diff;
325 return false;
326 }
327 };
328
329 //#endregion
330 //#region packages/packages/core/editor-variables/src/prop-types/font-variable-prop-type.ts
331 var fontVariablePropTypeUtil = (0, _elementor_editor_props.createPropUtils)("global-font-variable", _elementor_schema.z.string());
332
333 //#endregion
334 //#region packages/packages/core/editor-variables/src/create-style-variables-repository.ts
335 var createStyleVariablesRepository = () => {
336 const variables = {};
337 let subscription;
338 const subscribe = (cb) => {
339 subscription = cb;
340 return () => {
341 subscription = () => {};
342 };
343 };
344 const notify = () => {
345 if (typeof subscription === "function") subscription({ ...variables });
346 };
347 const shouldUpdate = (key, maybeUpdated) => {
348 if (!(key in variables)) return true;
349 if (variables[key].label !== maybeUpdated.label) return true;
350 if (variables[key].value !== maybeUpdated.value) return true;
351 if (!variables[key]?.deleted && maybeUpdated?.deleted) return true;
352 if (variables[key]?.deleted && !maybeUpdated?.deleted) return true;
353 return false;
354 };
355 const applyUpdates = (updatedVars) => {
356 let hasChanges = false;
357 for (const [key, variable] of Object.entries(updatedVars)) if (shouldUpdate(key, variable)) {
358 variables[key] = variable;
359 if (variable.type === fontVariablePropTypeUtil.key) fontEnqueue(variable.value);
360 hasChanges = true;
361 }
362 return hasChanges;
363 };
364 const fontEnqueue = (value) => {
365 if (!value) return;
366 try {
367 (0, _elementor_editor_v1_adapters.enqueueFont)(value);
368 } catch {}
369 };
370 const update = (updatedVars) => {
371 if (applyUpdates(updatedVars)) notify();
372 };
373 return {
374 subscribe,
375 update
376 };
377 };
378
379 //#endregion
380 //#region packages/packages/core/editor-variables/src/style-variables-repository.ts
381 var styleVariablesRepository = createStyleVariablesRepository();
382
383 //#endregion
384 //#region packages/packages/core/editor-variables/src/service.ts
385 var storage = new Storage();
386 var service = {
387 variables: () => {
388 return storage.load();
389 },
390 findIdByLabel(needle) {
391 const variableId = Object.entries(this.variables()).find(([, variable]) => variable.label === needle);
392 if (!variableId) throw new Error(`Variable with label ${needle} not found`);
393 return variableId[0];
394 },
395 findVariableByLabel(needle) {
396 return Object.values(this.variables()).find((variable) => variable.label === needle) || null;
397 },
398 getWatermark: () => {
399 return storage.state.watermark;
400 },
401 init: () => {
402 return service.load();
403 },
404 load: () => {
405 return apiClient.list().then((response) => {
406 const { success, data: payload } = response.data;
407 if (!success) throw new Error("Unexpected response from server");
408 return payload;
409 }).then((data) => {
410 const { variables, watermark } = data;
411 storage.fill(variables, watermark);
412 styleVariablesRepository.update(variables);
413 return variables;
414 });
415 },
416 create: ({ type, label, value }, options = {}) => {
417 return apiClient.create(type, label, value).then((response) => {
418 const { success, data: payload } = response.data;
419 if (!success) {
420 const errorMessage = payload?.message || (0, _wordpress_i18n.__)("Unexpected response from server", "elementor");
421 throw new Error(errorMessage);
422 }
423 return payload;
424 }).then((data) => {
425 const { variable, watermark } = data;
426 handleWatermark("RW", watermark);
427 const { id: variableId, ...createdVariable } = variable;
428 storage.add(variableId, createdVariable);
429 styleVariablesRepository.update({ [variableId]: createdVariable });
430 trackVariableEvent({
431 varType: type,
432 action: "save",
433 ...options.eventData
434 });
435 return {
436 id: variableId,
437 variable: createdVariable
438 };
439 });
440 },
441 update: (id, { label, value, type }, options = {}) => {
442 return apiClient.update(id, label, value, type).then((response) => {
443 const { success, data: payload } = response.data;
444 if (!success) {
445 const errorMessage = payload?.message || (0, _wordpress_i18n.__)("Unexpected response from server", "elementor");
446 throw new Error(errorMessage);
447 }
448 return payload;
449 }).then((data) => {
450 const { variable, watermark } = data;
451 handleWatermark("RW", watermark);
452 const { id: variableId, ...updatedVariable } = variable;
453 storage.update(variableId, updatedVariable);
454 styleVariablesRepository.update({ [variableId]: updatedVariable });
455 trackVariableEvent({
456 varType: updatedVariable.type,
457 action: "update",
458 ...options.eventData
459 });
460 return {
461 id: variableId,
462 variable: updatedVariable
463 };
464 });
465 },
466 delete: (id) => {
467 return apiClient.delete(id).then((response) => {
468 const { success, data: payload } = response.data;
469 if (!success) throw new Error("Unexpected response from server");
470 return payload;
471 }).then((data) => {
472 const { variable, watermark } = data;
473 handleWatermark("RW", watermark);
474 const { id: variableId, ...deletedVariable } = variable;
475 storage.update(variableId, deletedVariable);
476 styleVariablesRepository.update({ [variableId]: deletedVariable });
477 return {
478 id: variableId,
479 variable: deletedVariable
480 };
481 });
482 },
483 restore: (id, label, value, type) => {
484 return apiClient.restore(id, label, value, type).then((response) => {
485 const { success, data: payload } = response.data;
486 if (!success) throw new Error("Unexpected response from server");
487 return payload;
488 }).then((data) => {
489 const { variable, watermark } = data;
490 handleWatermark("RW", watermark);
491 const { id: variableId, ...restoredVariable } = variable;
492 storage.update(variableId, restoredVariable);
493 styleVariablesRepository.update({ [variableId]: restoredVariable });
494 return {
495 id: variableId,
496 variable: restoredVariable
497 };
498 });
499 },
500 batchSave: (originalVariables, currentVariables, deletedVariables) => {
501 const operations = buildOperationsArray(originalVariables, currentVariables, deletedVariables);
502 const batchPayload = {
503 operations,
504 watermark: storage.state.watermark
505 };
506 if (operations.length === 0) return Promise.resolve({
507 success: true,
508 watermark: storage.state.watermark,
509 operations: 0
510 });
511 return apiClient.batch(batchPayload).then((response) => {
512 const { success, data: payload } = response.data;
513 if (!success) throw new Error("Unexpected response from server");
514 return payload;
515 }).then((data) => {
516 const { results, watermark } = data;
517 handleWatermark("RW", watermark);
518 if (results) results.forEach((result) => {
519 const variableId = result.id;
520 if (result.variable) {
521 if (result.type === "create") storage.add(variableId, result.variable);
522 else storage.update(variableId, result.variable);
523 styleVariablesRepository.update({ [variableId]: result.variable });
524 }
525 });
526 return {
527 success: true,
528 watermark,
529 operations: operations.length
530 };
531 });
532 }
533 };
534 var handleWatermark = (operation, newWatermark) => {
535 if (storage.watermarkDiff(operation, newWatermark)) setTimeout(() => service.load(), 500);
536 storage.watermark(newWatermark);
537 };
538 var applyLocalMutation = (action, variableWithId, watermark) => {
539 const { id: variableId, ...variable } = variableWithId;
540 handleWatermark("RW", watermark);
541 if (action === "create") storage.add(variableId, variable);
542 else storage.update(variableId, variable);
543 styleVariablesRepository.update({ [variableId]: variable });
544 };
545
546 //#endregion
547 //#region packages/packages/core/editor-variables/src/transformers/utils/resolve-css-variable.ts
548 var resolveCssVariable = (id, variable) => {
549 let name = id;
550 let fallbackValue = "";
551 if (variable) fallbackValue = variable.value;
552 if (variable && !variable.deleted) name = variable.label;
553 if (!name.trim()) return null;
554 const validCssVariableName = `--${name}`;
555 if (!fallbackValue.trim()) return `var(${validCssVariableName})`;
556 return `var(${validCssVariableName}, ${fallbackValue})`;
557 };
558
559 //#endregion
560 //#region packages/packages/core/editor-variables/src/transformers/inheritance-transformer.tsx
561 var inheritanceTransformer = (0, _elementor_editor_canvas.createTransformer)((id) => {
562 const variable = service.variables()[id];
563 if (!variable) return /* @__PURE__ */ react.createElement("span", null, (0, _wordpress_i18n.__)("Missing variable", "elementor"));
564 const showColorIndicator = variable.type === colorVariablePropTypeUtil.key;
565 const css = resolveCssVariable(id, variable);
566 return /* @__PURE__ */ react.createElement(_elementor_ui.Stack, {
567 direction: "row",
568 spacing: .5,
569 sx: { paddingInline: "1px" },
570 alignItems: "center"
571 }, showColorIndicator && /* @__PURE__ */ react.createElement(ColorIndicator, {
572 size: "inherit",
573 value: variable.value
574 }), /* @__PURE__ */ react.createElement(_elementor_ui.Typography, {
575 variant: "caption",
576 overflow: "hidden",
577 whiteSpace: "nowrap",
578 textOverflow: "ellipsis"
579 }, css));
580 });
581
582 //#endregion
583 //#region packages/packages/core/editor-variables/src/transformers/variable-transformer.ts
584 var variableTransformer = (0, _elementor_editor_canvas.createTransformer)((idOrLabel, { key }) => {
585 const targetVariable = service.variables()[idOrLabel] || service.findVariableByLabel(idOrLabel);
586 if (!targetVariable) return null;
587 if ((0, _elementor_editor_canvas.isGridTrackProperty)(key)) return (0, _elementor_editor_canvas.formatGridTrackRepeat)(parseInt((targetVariable.value ?? "").trim(), 10));
588 return resolveCssVariable(service.findIdByLabel(targetVariable.label), targetVariable);
589 });
590
591 //#endregion
592 //#region packages/packages/core/editor-variables/src/variables-registry/create-variable-type-registry.ts
593 function createVariableTypeRegistry() {
594 const variableTypes = {};
595 const registerVariableType = ({ key, icon, startIcon, valueField, propTypeUtil, variableType, defaultValue, selectionFilter, valueTransformer, styleTransformer, fallbackPropTypeUtil, isCompatible, emptyState, isActive = true, menuActionsFactory }) => {
596 const variableTypeKey = key ?? propTypeUtil.key;
597 if (!isCompatible) isCompatible = (propType, variable) => {
598 if ("union" === propType.kind) {
599 if (variable.type in propType.prop_types) return true;
600 }
601 return false;
602 };
603 variableTypes[variableTypeKey] = {
604 icon,
605 startIcon,
606 valueField,
607 propTypeUtil,
608 variableType,
609 defaultValue,
610 selectionFilter,
611 valueTransformer,
612 fallbackPropTypeUtil,
613 isCompatible,
614 emptyState,
615 isActive,
616 menuActionsFactory
617 };
618 registerTransformer(propTypeUtil.key, styleTransformer);
619 registerInheritanceTransformer(propTypeUtil.key);
620 };
621 const registerTransformer = (key, transformer) => {
622 _elementor_editor_canvas.styleTransformersRegistry.register(key, transformer ?? variableTransformer);
623 };
624 const registerInheritanceTransformer = (key) => {
625 _elementor_editor_canvas.stylesInheritanceTransformersRegistry.register(key, inheritanceTransformer);
626 };
627 const getVariableType = (key) => {
628 return variableTypes[key];
629 };
630 const getVariableTypes = () => {
631 return variableTypes;
632 };
633 const hasVariableType = (key) => {
634 return key in variableTypes && !!variableTypes[key].isActive;
635 };
636 return {
637 registerVariableType,
638 getVariableType,
639 getVariableTypes,
640 hasVariableType
641 };
642 }
643
644 //#endregion
645 //#region packages/packages/core/editor-variables/src/variables-registry/variable-type-registry.ts
646 var { registerVariableType, getVariableType, getVariableTypes, hasVariableType } = createVariableTypeRegistry();
647 function getMenuActionsForVariable(variableType, context) {
648 const typeOptions = getVariableType(variableType);
649 if (typeOptions?.menuActionsFactory) return typeOptions.menuActionsFactory(context);
650 return [];
651 }
652
653 //#endregion
654 //#region packages/packages/core/editor-variables/src/components/ui/delete-confirmation-dialog.tsx
655 var DeleteConfirmationDialog = ({ open, label, closeDialog, onConfirm }) => {
656 return /* @__PURE__ */ react.createElement(_elementor_editor_ui.ConfirmationDialog, {
657 open,
658 onClose: closeDialog
659 }, /* @__PURE__ */ react.createElement(_elementor_editor_ui.ConfirmationDialog.Title, null, (0, _wordpress_i18n.__)("Delete this variable?", "elementor")), /* @__PURE__ */ react.createElement(_elementor_editor_ui.ConfirmationDialog.Content, null, /* @__PURE__ */ react.createElement(_elementor_editor_ui.ConfirmationDialog.ContentText, null, (0, _wordpress_i18n.__)("All elements using", "elementor"), "\xA0", /* @__PURE__ */ react.createElement(_elementor_ui.Typography, {
660 variant: "subtitle2",
661 component: "span",
662 sx: { lineBreak: "anywhere" }
663 }, label), "\xA0", (0, _wordpress_i18n.__)("will keep their current values, but the variable itself will be removed.", "elementor"))), /* @__PURE__ */ react.createElement(_elementor_editor_ui.ConfirmationDialog.Actions, {
664 onClose: closeDialog,
665 onConfirm
666 }));
667 };
668
669 //#endregion
670 //#region packages/packages/core/editor-variables/src/hooks/use-permissions.ts
671 var usePermissions = () => {
672 const { canUser, isAdmin } = (0, _elementor_editor_current_user.useCurrentUserCapabilities)();
673 return {
674 canAssign: () => canUser("edit_posts"),
675 canUnlink: () => canUser("edit_posts"),
676 canAdd: () => isAdmin,
677 canDelete: () => isAdmin,
678 canEdit: () => isAdmin,
679 canRestore: () => isAdmin,
680 canManageSettings: () => isAdmin
681 };
682 };
683
684 //#endregion
685 //#region packages/packages/core/editor-variables/src/components/ui/empty-state.tsx
686 var EmptyState = ({ icon, title, message, onAdd, children }) => {
687 const canAdd = usePermissions().canAdd();
688 const displayTitle = canAdd ? title : (0, _wordpress_i18n.__)("There are no variables", "elementor");
689 const displayMessage = canAdd ? message : (0, _wordpress_i18n.__)("With your current role, you can only connect and detach variables.", "elementor");
690 return /* @__PURE__ */ react.createElement(Content, {
691 title: displayTitle,
692 message: displayMessage,
693 icon
694 }, children || onAdd && /* @__PURE__ */ react.createElement(_elementor_ui.Button, {
695 variant: "outlined",
696 color: "secondary",
697 size: "small",
698 onClick: onAdd
699 }, (0, _wordpress_i18n.__)("Create a variable", "elementor")));
700 };
701 function Content({ title, message, icon, children }) {
702 return /* @__PURE__ */ react.createElement(_elementor_ui.Stack, {
703 gap: 1,
704 alignItems: "center",
705 justifyContent: "flex-start",
706 height: "100%",
707 color: "text.secondary",
708 sx: {
709 p: 2.5,
710 pt: 8,
711 pb: 5.5
712 }
713 }, icon, /* @__PURE__ */ react.createElement(_elementor_ui.Typography, {
714 align: "center",
715 variant: "subtitle2"
716 }, title), /* @__PURE__ */ react.createElement(_elementor_ui.Typography, {
717 align: "center",
718 variant: "caption",
719 maxWidth: "180px"
720 }, message), children);
721 }
722
723 //#endregion
724 //#region packages/packages/core/editor-variables/src/components/ui/no-search-results.tsx
725 var NoSearchResults = ({ searchValue, onClear, icon }) => {
726 return /* @__PURE__ */ react.createElement(_elementor_ui.Stack, {
727 gap: 1,
728 alignItems: "center",
729 justifyContent: "center",
730 p: 2.5,
731 color: "text.secondary",
732 sx: {
733 pb: 3.5,
734 pt: 8
735 }
736 }, icon, /* @__PURE__ */ react.createElement(_elementor_ui.Typography, {
737 align: "center",
738 variant: "subtitle2"
739 }, (0, _wordpress_i18n.__)("Sorry, nothing matched", "elementor"), /* @__PURE__ */ react.createElement("br", null), "“", searchValue, "”."), /* @__PURE__ */ react.createElement(_elementor_ui.Typography, {
740 align: "center",
741 variant: "caption",
742 sx: {
743 display: "flex",
744 flexDirection: "column"
745 }
746 }, (0, _wordpress_i18n.__)("Try something else.", "elementor"), /* @__PURE__ */ react.createElement(_elementor_ui.Link, {
747 color: "text.secondary",
748 variant: "caption",
749 component: "button",
750 onClick: onClear
751 }, (0, _wordpress_i18n.__)("Clear & try again", "elementor"))));
752 };
753
754 //#endregion
755 //#region packages/packages/core/editor-variables/src/components/variables-manager/hooks/use-auto-edit.ts
756 var useAutoEdit = () => {
757 const [autoEditVariableId, setAutoEditVariableId] = (0, react.useState)(void 0);
758 return {
759 autoEditVariableId,
760 startAutoEdit: (0, react.useCallback)((variableId) => {
761 setAutoEditVariableId(variableId);
762 }, []),
763 handleAutoEditComplete: (0, react.useCallback)(() => {
764 setTimeout(() => {
765 setAutoEditVariableId(void 0);
766 }, 100);
767 }, [])
768 };
769 };
770
771 //#endregion
772 //#region packages/packages/core/editor-variables/src/components/variables-manager/hooks/use-error-navigation.ts
773 var useErrorNavigation = () => {
774 const currentIndexRef = (0, react.useRef)(0);
775 return {
776 createNavigationCallback: (0, react.useCallback)((ids, onNavigate, onComplete) => {
777 return () => {
778 if (!ids?.length) return;
779 const currentIndex = currentIndexRef.current;
780 const currentId = ids[currentIndex];
781 if (currentId) {
782 onNavigate(currentId);
783 const nextIndex = currentIndex + 1;
784 if (nextIndex >= ids.length) {
785 onComplete();
786 currentIndexRef.current = 0;
787 } else currentIndexRef.current = nextIndex;
788 }
789 };
790 }, []),
791 resetNavigation: (0, react.useCallback)(() => {
792 currentIndexRef.current = 0;
793 }, [])
794 };
795 };
796
797 //#endregion
798 //#region packages/packages/core/editor-variables/src/context/variable-type-context.tsx
799 var VariableTypeContext = (0, react.createContext)(null);
800 function VariableTypeProvider({ children, propTypeKey }) {
801 return /* @__PURE__ */ react.createElement(VariableTypeContext.Provider, { value: propTypeKey }, children);
802 }
803 function useVariableType() {
804 const context = (0, react.useContext)(VariableTypeContext);
805 if (context === null) throw new Error("useVariableType must be used within a VariableTypeProvider");
806 return getVariableType(context);
807 }
808
809 //#endregion
810 //#region packages/packages/core/editor-variables/src/utils/filter-by-search.ts
811 function filterBySearch(variables, searchValue) {
812 const lowerSearchValue = searchValue.toLowerCase();
813 return variables.filter((variable) => variable.label.toLowerCase().includes(lowerSearchValue));
814 }
815
816 //#endregion
817 //#region packages/packages/core/editor-variables/src/utils/variables-to-list.ts
818 var variablesToList = (variables) => {
819 return Object.entries(variables).map(([key, variable]) => ({
820 key,
821 ...variable
822 }));
823 };
824 var toNormalizedVariable = ({ key, label, value, order, sync_to_v3: syncToV3 }) => ({
825 key,
826 label,
827 value,
828 order,
829 sync_to_v3: syncToV3
830 });
831 var applySelectionFilters = (variables, variableTypes) => {
832 const grouped = {};
833 variables.forEach((item) => {
834 var _a;
835 return (grouped[_a = item.type] ?? (grouped[_a] = [])).push(item);
836 });
837 return Object.entries(grouped).flatMap(([type, vars]) => {
838 const filter = variableTypes[type]?.selectionFilter;
839 const normalized = vars.map(toNormalizedVariable);
840 return (filter?.(normalized) ?? normalized).map((v) => ({
841 ...v,
842 type
843 }));
844 });
845 };
846
847 //#endregion
848 //#region packages/packages/core/editor-variables/src/hooks/use-prop-variables.ts
849 var getVariables = (includeDeleted = true) => {
850 const variables = service.variables();
851 if (includeDeleted) return variables;
852 return Object.fromEntries(Object.entries(variables).filter(([, variable]) => !variable.deleted));
853 };
854 var hasVariable = (key) => {
855 return getVariables()[key] !== void 0;
856 };
857 var useVariable = (key) => {
858 return getVariable(key);
859 };
860 function getVariable(key) {
861 const variables = getVariables();
862 if (!variables?.[key]) return null;
863 return {
864 ...variables[key],
865 key
866 };
867 }
868 var useFilteredVariables = (searchValue, propTypeKey) => {
869 const baseVariables = usePropVariables(propTypeKey);
870 const typeFilteredVariables = useVariableSelectionFilter(baseVariables);
871 const searchFilteredVariables = filterBySearch(typeFilteredVariables, searchValue);
872 return {
873 list: searchFilteredVariables.sort((a, b) => {
874 return (a.order ?? Number.MAX_SAFE_INTEGER) - (b.order ?? Number.MAX_SAFE_INTEGER);
875 }),
876 hasMatches: searchFilteredVariables.length > 0,
877 isSourceNotEmpty: typeFilteredVariables.length > 0,
878 hasNoCompatibleVariables: baseVariables.length > 0 && typeFilteredVariables.length === 0
879 };
880 };
881 var useVariableSelectionFilter = (variables) => {
882 const { selectionFilter } = useVariableType();
883 const { propType } = (0, _elementor_editor_controls.useBoundProp)();
884 return selectionFilter ? selectionFilter(variables, propType) : variables;
885 };
886 var usePropVariables = (propKey) => {
887 return (0, react.useMemo)(() => normalizeVariables(propKey), [propKey]);
888 };
889 var getMatchingTypes = (propKey) => {
890 const matchingTypes = [];
891 const allTypes = getVariableTypes();
892 const variableType = getVariableType(propKey);
893 Object.entries(allTypes).forEach(([key, typeOptions]) => {
894 if (variableType.variableType === typeOptions.variableType) matchingTypes.push(key);
895 });
896 return matchingTypes;
897 };
898 var normalizeVariables = (propKey) => {
899 const variables = getVariables(false);
900 const matchingTypes = getMatchingTypes(propKey);
901 return variablesToList(variables).filter((variable) => matchingTypes.includes(variable.type)).map(toNormalizedVariable);
902 };
903 var extractId = ({ id }) => id;
904 var createVariable = (newVariable, options) => {
905 return service.create(newVariable, options).then(extractId);
906 };
907 var updateVariable = (updateId, { value, label, type }, options) => {
908 return service.update(updateId, {
909 value,
910 label,
911 type
912 }, options).then(extractId);
913 };
914 var deleteVariable = (deleteId) => {
915 return service.delete(deleteId).then(extractId);
916 };
917 var restoreVariable = (restoreId, label, value, type) => {
918 return service.restore(restoreId, label, value, type).then(extractId);
919 };
920
921 //#endregion
922 //#region packages/packages/core/editor-variables/src/utils/duplicate-label.ts
923 var COPY_SUFFIX = "-Copy";
924 var trimToFit = (base, suffix) => {
925 const combined = base + suffix;
926 if (combined.length <= 50) return combined;
927 return base.slice(0, 50 - suffix.length) + suffix;
928 };
929 var generateDuplicateLabel = (originalLabel, existingLabels) => {
930 const labelsSet = new Set(existingLabels);
931 const firstCandidate = trimToFit(originalLabel, COPY_SUFFIX);
932 if (!labelsSet.has(firstCandidate)) return firstCandidate;
933 for (let i = 2; i <= labelsSet.size + 1; i++) {
934 const candidate = trimToFit(originalLabel, `${COPY_SUFFIX}-${i}`);
935 if (!labelsSet.has(candidate)) return candidate;
936 }
937 return firstCandidate;
938 };
939
940 //#endregion
941 //#region packages/packages/core/editor-variables/src/components/variables-manager/hooks/use-variables-manager-state.ts
942 var useVariablesManagerState = () => {
943 const [variables, setVariables] = (0, react.useState)(() => getVariables(false));
944 const [deletedVariables, setDeletedVariables] = (0, react.useState)([]);
945 const [isSaveDisabled, setIsSaveDisabled] = (0, react.useState)(false);
946 const [isDirty, setIsDirty] = (0, react.useState)(false);
947 const [isSaving, setIsSaving] = (0, react.useState)(false);
948 const [searchValue, setSearchValue] = (0, react.useState)("");
949 (0, react.useEffect)(() => {
950 const handleStorageUpdated = () => {
951 setVariables(getVariables(false));
952 setDeletedVariables([]);
953 setIsDirty(false);
954 };
955 window.addEventListener(STORAGE_UPDATED_EVENT, handleStorageUpdated);
956 return () => {
957 window.removeEventListener(STORAGE_UPDATED_EVENT, handleStorageUpdated);
958 };
959 }, []);
960 const handleOnChange = (0, react.useCallback)((newVariables) => {
961 if (Object.entries(newVariables).some(([id, newVar]) => {
962 const existingVar = variables[id];
963 if (!existingVar) return true;
964 return existingVar.label !== newVar.label || existingVar.value !== newVar.value || existingVar.order !== newVar.order || existingVar.type !== newVar.type || (existingVar.sync_to_v3 ?? false) !== (newVar.sync_to_v3 ?? false);
965 })) {
966 setVariables({
967 ...variables,
968 ...newVariables
969 });
970 setIsDirty(true);
971 }
972 }, [variables]);
973 const createVariable = (0, react.useCallback)((type, defaultName, defaultValue) => {
974 const newId = generateTempId();
975 const newVariable = {
976 id: newId,
977 label: defaultName.trim(),
978 value: defaultValue.trim(),
979 type
980 };
981 setVariables((prev) => ({
982 ...prev,
983 [newId]: newVariable
984 }));
985 setIsDirty(true);
986 return newId;
987 }, []);
988 const duplicateVariable = (0, react.useCallback)((sourceId) => {
989 const newId = generateTempId();
990 setVariables((prev) => {
991 const source = prev[sourceId];
992 if (!source || source.deleted) return prev;
993 const existingLabels = Object.values(prev).filter((v) => !v.deleted).map((v) => v.label);
994 return {
995 ...prev,
996 [newId]: {
997 label: generateDuplicateLabel(source.label, existingLabels),
998 value: source.value,
999 type: source.type
1000 }
1001 };
1002 });
1003 setIsDirty(true);
1004 return newId;
1005 }, []);
1006 const handleDeleteVariable = (0, react.useCallback)((itemId) => {
1007 setDeletedVariables((prev) => [...prev, itemId]);
1008 setVariables((prev) => ({
1009 ...prev,
1010 [itemId]: {
1011 ...prev[itemId],
1012 deleted: true
1013 }
1014 }));
1015 setIsDirty(true);
1016 }, []);
1017 const handleStartSync = (0, react.useCallback)((itemId) => {
1018 setVariables((prev) => ({
1019 ...prev,
1020 [itemId]: {
1021 ...prev[itemId],
1022 sync_to_v3: true
1023 }
1024 }));
1025 setIsDirty(true);
1026 }, []);
1027 const handleStopSync = (0, react.useCallback)((itemId) => {
1028 setVariables((prev) => ({
1029 ...prev,
1030 [itemId]: {
1031 ...prev[itemId],
1032 sync_to_v3: false
1033 }
1034 }));
1035 setIsDirty(true);
1036 }, []);
1037 const handleSearch = (searchTerm) => {
1038 setSearchValue(searchTerm);
1039 };
1040 const handleSave = (0, react.useCallback)(async () => {
1041 const originalVariables = getVariables(false);
1042 setIsSaving(true);
1043 const result = await service.batchSave(originalVariables, variables, deletedVariables);
1044 if (result.success) {
1045 await service.load();
1046 const updatedVariables = service.variables();
1047 setVariables(updatedVariables);
1048 setDeletedVariables([]);
1049 setIsDirty(false);
1050 }
1051 return { success: result.success };
1052 }, [variables, deletedVariables]);
1053 return {
1054 variables: (0, react.useCallback)(() => {
1055 const searchFiltered = filterBySearch(applySelectionFilters(variablesToList(variables).filter((v) => !v.deleted), getVariableTypes()), searchValue);
1056 return Object.fromEntries(searchFiltered.map(({ key, ...rest }) => [key, rest]));
1057 }, [variables, searchValue])(),
1058 deletedVariables,
1059 isDirty,
1060 isSaveDisabled,
1061 handleOnChange,
1062 createVariable,
1063 duplicateVariable,
1064 handleDeleteVariable,
1065 handleStartSync,
1066 handleStopSync,
1067 handleSave,
1068 isSaving,
1069 handleSearch,
1070 searchValue,
1071 setIsSaving,
1072 setIsSaveDisabled
1073 };
1074 };
1075
1076 //#endregion
1077 //#region packages/packages/core/editor-variables/src/hooks/use-quota-permissions.ts
1078 var useQuotaPermissions = (variableType) => {
1079 const quotaConfig = {
1080 ...window.ElementorVariablesQuotaConfig ?? {},
1081 ...window.ElementorVariablesQuotaConfigExtended ?? {}
1082 };
1083 const hasLegacySupport = quotaConfig[variableType] === void 0 && window.elementorPro;
1084 const limit = quotaConfig[variableType] || 0;
1085 const hasPermission = hasLegacySupport || limit > 0;
1086 return {
1087 canAdd: () => hasPermission,
1088 canEdit: () => hasPermission
1089 };
1090 };
1091
1092 //#endregion
1093 //#region packages/packages/core/editor-variables/src/components/ui/variable-promotion-chip.tsx
1094 var VariablePromotionChip = (0, react.forwardRef)(({ variableType, upgradeUrl, trackingData }, ref) => {
1095 const [isOpen, setIsOpen] = (0, react.useState)(false);
1096 (0, _elementor_editor_ui.useCanvasClickHandler)(isOpen, () => setIsOpen(false));
1097 const toggle = (0, react.useCallback)(() => {
1098 setIsOpen((prev) => {
1099 if (!prev) (0, _elementor_editor_controls.trackViewPromotion)(trackingData);
1100 return !prev;
1101 });
1102 }, [trackingData]);
1103 (0, react.useImperativeHandle)(ref, () => ({ toggle }), [toggle]);
1104 const title = (0, _wordpress_i18n.sprintf)((0, _wordpress_i18n.__)("%s variables", "elementor"), (0, _elementor_utils.capitalize)(variableType));
1105 const content = (0, _wordpress_i18n.sprintf)((0, _wordpress_i18n.__)("Upgrade to continue creating and editing %s variables.", "elementor"), variableType);
1106 return /* @__PURE__ */ react.createElement(_elementor_editor_ui.PromotionPopover, {
1107 open: isOpen,
1108 title,
1109 content,
1110 ctaText: (0, _wordpress_i18n.__)("Upgrade now", "elementor"),
1111 ctaUrl: upgradeUrl,
1112 onClose: (e) => {
1113 e.stopPropagation();
1114 setIsOpen(false);
1115 },
1116 onCtaClick: () => (0, _elementor_editor_controls.trackUpgradePromotionClick)(trackingData)
1117 }, /* @__PURE__ */ react.createElement(_elementor_ui.Box, {
1118 onClick: (e) => {
1119 e.stopPropagation();
1120 toggle();
1121 },
1122 sx: {
1123 cursor: "pointer",
1124 display: "inline-flex"
1125 }
1126 }, /* @__PURE__ */ react.createElement(_elementor_editor_ui.PromotionChip, null)));
1127 });
1128
1129 //#endregion
1130 //#region packages/packages/core/editor-variables/src/components/variables-manager/variables-manager-create-menu.tsx
1131 var TRACKING_DATA$1 = {
1132 target_name: "variables_manager",
1133 target_location: "variables_manager",
1134 location_l1: "create variable menu"
1135 };
1136 var SIZE$6 = "tiny";
1137 var VariableManagerCreateMenu = ({ variables, onCreate, menuState, outlinedTrigger = false }) => {
1138 const buttonRef = (0, react.useRef)(null);
1139 const variableTypes = getVariableTypes();
1140 const menuOptionConfigs = (0, react.useMemo)(() => Object.entries(variableTypes).filter(([, variable]) => !!variable.defaultValue).map(([key, variable]) => ({
1141 key,
1142 propTypeKey: variable.propTypeUtil.key,
1143 variableType: variable.variableType,
1144 defaultValue: variable.defaultValue || "",
1145 icon: variable.icon
1146 })), [variableTypes]);
1147 return /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement(_elementor_ui.IconButton, {
1148 ...(0, _elementor_ui.bindTrigger)(menuState),
1149 ref: buttonRef,
1150 size: SIZE$6,
1151 variant: outlinedTrigger ? "outlined" : void 0,
1152 "aria-label": (0, _wordpress_i18n.__)("Add variable", "elementor")
1153 }, /* @__PURE__ */ react.createElement(_elementor_icons.PlusIcon, { fontSize: SIZE$6 })), /* @__PURE__ */ react.createElement(_elementor_ui.Menu, {
1154 disablePortal: true,
1155 MenuListProps: { dense: true },
1156 PaperProps: { elevation: 6 },
1157 ...(0, _elementor_ui.bindMenu)(menuState),
1158 anchorEl: buttonRef.current,
1159 anchorOrigin: {
1160 vertical: "bottom",
1161 horizontal: "right"
1162 },
1163 transformOrigin: {
1164 vertical: "top",
1165 horizontal: "right"
1166 },
1167 "data-testid": "variable-manager-create-menu"
1168 }, menuOptionConfigs.map((config) => /* @__PURE__ */ react.createElement(MenuOption, {
1169 key: config.key,
1170 config,
1171 variables,
1172 onCreate,
1173 onClose: menuState.close
1174 }))));
1175 };
1176 var MenuOption = ({ config, variables, onCreate, onClose }) => {
1177 const promotionRef = (0, react.useRef)(null);
1178 const userQuotaPermissions = useQuotaPermissions(config.propTypeKey);
1179 const displayName = (0, _elementor_utils.capitalize)(config.variableType);
1180 const isDisabled = !userQuotaPermissions.canAdd();
1181 const handleClick = () => {
1182 if (isDisabled) {
1183 promotionRef.current?.toggle();
1184 return;
1185 }
1186 const defaultName = getDefaultName(variables, config.variableType);
1187 onCreate(config.key, defaultName, config.defaultValue);
1188 trackVariablesManagerEvent({
1189 action: "add",
1190 varType: config.variableType
1191 });
1192 onClose();
1193 };
1194 return /* @__PURE__ */ react.createElement(_elementor_ui.MenuItem, {
1195 onClick: handleClick,
1196 sx: {
1197 gap: 1.5,
1198 cursor: "pointer"
1199 }
1200 }, (0, react.createElement)(config.icon, {
1201 fontSize: SIZE$6,
1202 color: isDisabled ? "disabled" : "action"
1203 }), /* @__PURE__ */ react.createElement(_elementor_ui.Typography, {
1204 variant: "caption",
1205 color: isDisabled ? "text.disabled" : "text.primary"
1206 }, displayName), isDisabled && /* @__PURE__ */ react.createElement(VariablePromotionChip, {
1207 variableType: config.variableType,
1208 upgradeUrl: `https://go.elementor.com/go-pro-manager-${config.variableType}-variable/`,
1209 ref: promotionRef,
1210 trackingData: TRACKING_DATA$1
1211 }));
1212 };
1213 var getDefaultName = (variables, baseName) => {
1214 const pattern = new RegExp(`^${baseName}-(\\d+)$`, "i");
1215 const takenNumbers = /* @__PURE__ */ new Set();
1216 Object.values(variables).forEach((variable) => {
1217 const match = variable.label.match(pattern);
1218 if (match) takenNumbers.add(parseInt(match[1], 10));
1219 });
1220 let counter = 1;
1221 while (takenNumbers.has(counter)) counter++;
1222 return `${baseName}-${counter}`;
1223 };
1224
1225 //#endregion
1226 //#region packages/packages/core/editor-variables/src/components/variables-manager/ui/variable-table-cell.tsx
1227 var VariableTableCell = ({ children, isHeader, width, maxWidth, align, noPadding, sx }) => {
1228 const baseSx = {
1229 maxWidth: maxWidth ?? 150,
1230 cursor: "initial",
1231 typography: "caption",
1232 ...isHeader && {
1233 color: "text.primary",
1234 fontWeight: "bold"
1235 },
1236 ...isHeader && !noPadding && { padding: "10px 16px" },
1237 ...width && { width },
1238 ...sx
1239 };
1240 return /* @__PURE__ */ react.createElement(_elementor_ui.TableCell, {
1241 size: "small",
1242 padding: noPadding ? "none" : void 0,
1243 align,
1244 sx: baseSx
1245 }, children);
1246 };
1247
1248 //#endregion
1249 //#region packages/packages/core/editor-variables/src/components/fields/label-field.tsx
1250 function isLabelEqual(a, b) {
1251 return a.trim().toLowerCase() === b.trim().toLowerCase();
1252 }
1253 var useLabelError = (initialError) => {
1254 const [error, setError] = (0, react.useState)(initialError ?? {
1255 value: "",
1256 message: ""
1257 });
1258 return {
1259 labelFieldError: error,
1260 setLabelFieldError: setError
1261 };
1262 };
1263 var LabelField = ({ value, error, onChange, id, onErrorChange, size = "tiny", focusOnShow = false, selectOnShow = false, showWarningInfotip = false, variables, onKeyDown }) => {
1264 const [label, setLabel] = (0, react.useState)(value);
1265 const [errorMessage, setErrorMessage] = (0, react.useState)("");
1266 const fieldRef = (0, react.useRef)(null);
1267 const handleChange = (newValue) => {
1268 setLabel(newValue);
1269 const errorMsg2 = validateLabel(newValue, variables);
1270 setErrorMessage(errorMsg2);
1271 onErrorChange?.(errorMsg2);
1272 onChange(isLabelEqual(newValue, error?.value ?? "") || errorMsg2 ? "" : newValue);
1273 };
1274 let errorMsg = errorMessage;
1275 if (isLabelEqual(label, error?.value ?? "") && error?.message) errorMsg = error.message;
1276 const hintMsg = !errorMsg ? labelHint(label) : "";
1277 const textField = /* @__PURE__ */ react.createElement(_elementor_ui.TextField, {
1278 ref: fieldRef,
1279 id,
1280 size,
1281 fullWidth: true,
1282 value: label,
1283 error: !!errorMsg,
1284 onChange: (e) => handleChange(e.target.value),
1285 inputProps: {
1286 maxLength: 50,
1287 ...selectOnShow && { onFocus: (e) => e.target.select() },
1288 "aria-label": "Name",
1289 onKeyDown
1290 },
1291 autoFocus: focusOnShow
1292 });
1293 if (showWarningInfotip) {
1294 const tooltipWidth = Math.max(240, fieldRef.current?.getBoundingClientRect().width ?? 240);
1295 return /* @__PURE__ */ react.createElement(_elementor_editor_ui.WarningInfotip, {
1296 open: Boolean(errorMsg || hintMsg),
1297 text: errorMsg || hintMsg,
1298 placement: "bottom-start",
1299 width: tooltipWidth,
1300 offset: [0, -15],
1301 ...hintMsg && { hasError: false }
1302 }, textField);
1303 }
1304 return textField;
1305 };
1306
1307 //#endregion
1308 //#region packages/packages/core/editor-variables/src/components/variables-manager/variable-editable-cell.tsx
1309 var VariableEditableCell = react.memo(({ initialValue, children, editableElement, onChange, prefixElement, autoEdit = false, onRowRef, onAutoEditComplete, gap = 1, fieldType, disabled = false }) => {
1310 const [value, setValue] = (0, react.useState)(initialValue);
1311 const [isEditing, setIsEditing] = (0, react.useState)(false);
1312 const { labelFieldError, setLabelFieldError } = useLabelError();
1313 const [valueFieldError, setValueFieldError] = (0, react.useState)("");
1314 const rowRef = (0, react.useRef)(null);
1315 const handleSave = (0, react.useCallback)(() => {
1316 if (!(fieldType === "label" && labelFieldError?.message || fieldType === "value" && valueFieldError)) onChange(value);
1317 setIsEditing(false);
1318 }, [
1319 value,
1320 onChange,
1321 fieldType,
1322 labelFieldError,
1323 valueFieldError
1324 ]);
1325 (0, react.useEffect)(() => {
1326 onRowRef?.(rowRef?.current);
1327 }, [onRowRef]);
1328 (0, react.useEffect)(() => {
1329 if (autoEdit && !isEditing && !disabled) {
1330 setIsEditing(true);
1331 onAutoEditComplete?.();
1332 }
1333 }, [
1334 autoEdit,
1335 isEditing,
1336 onAutoEditComplete,
1337 disabled
1338 ]);
1339 const handleDoubleClick = () => {
1340 if (disabled) return;
1341 setIsEditing(true);
1342 };
1343 const handleKeyDown = (event) => {
1344 if (disabled) return;
1345 if (event.key === "Enter") handleSave();
1346 else if (event.key === "Escape") setIsEditing(false);
1347 if (event.key === " " && !isEditing) {
1348 event.preventDefault();
1349 setIsEditing(true);
1350 }
1351 };
1352 const handleChange = (0, react.useCallback)((newValue) => {
1353 setValue(newValue);
1354 }, []);
1355 const handleValidationChange = (0, react.useCallback)((errorMsg) => {
1356 if (fieldType === "label") setLabelFieldError({
1357 value,
1358 message: errorMsg
1359 });
1360 else setValueFieldError(errorMsg);
1361 }, [
1362 fieldType,
1363 value,
1364 setLabelFieldError,
1365 setValueFieldError
1366 ]);
1367 let currentError;
1368 if (fieldType === "label") currentError = labelFieldError;
1369 else if (fieldType === "value") currentError = {
1370 value,
1371 message: valueFieldError
1372 };
1373 const editableContent = editableElement({
1374 value,
1375 onChange: handleChange,
1376 onValidationChange: handleValidationChange,
1377 error: currentError
1378 });
1379 if (isEditing) return /* @__PURE__ */ react.createElement(_elementor_ui.ClickAwayListener, { onClickAway: handleSave }, /* @__PURE__ */ react.createElement(_elementor_ui.Stack, {
1380 ref: rowRef,
1381 direction: "row",
1382 alignItems: "center",
1383 gap,
1384 onDoubleClick: handleDoubleClick,
1385 onKeyDown: handleKeyDown,
1386 tabIndex: 0,
1387 role: "button",
1388 "aria-label": "Double click or press Space to edit"
1389 }, prefixElement, editableContent));
1390 return /* @__PURE__ */ react.createElement(_elementor_ui.Stack, {
1391 ref: rowRef,
1392 direction: "row",
1393 alignItems: "center",
1394 gap,
1395 onDoubleClick: handleDoubleClick,
1396 onKeyDown: handleKeyDown,
1397 tabIndex: disabled ? -1 : 0,
1398 role: "button",
1399 "aria-label": disabled ? "" : "Double click or press Space to edit"
1400 }, prefixElement, children);
1401 });
1402
1403 //#endregion
1404 //#region packages/packages/core/editor-variables/src/components/variables-manager/ui/variable-edit-menu.tsx
1405 var VariableEditMenu = ({ menuActions, disabled, itemId }) => {
1406 const menuState = (0, _elementor_ui.usePopupState)({ variant: "popover" });
1407 const triggerProps = (0, _elementor_ui.bindTrigger)(menuState);
1408 return /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement(_elementor_ui.IconButton, {
1409 ...triggerProps,
1410 disabled,
1411 size: "tiny",
1412 onClick: (e) => {
1413 e.stopPropagation();
1414 triggerProps.onClick?.(e);
1415 }
1416 }, /* @__PURE__ */ react.createElement(_elementor_icons.DotsVerticalIcon, { fontSize: "tiny" })), /* @__PURE__ */ react.createElement(_elementor_ui.Menu, {
1417 disablePortal: true,
1418 MenuListProps: { dense: true },
1419 PaperProps: { elevation: 6 },
1420 ...(0, _elementor_ui.bindMenu)(menuState),
1421 anchorEl: menuState.anchorEl,
1422 anchorOrigin: {
1423 vertical: "bottom",
1424 horizontal: "right"
1425 },
1426 transformOrigin: {
1427 vertical: "top",
1428 horizontal: "right"
1429 },
1430 open: menuState.isOpen,
1431 onClose: menuState.close
1432 }, menuActions.map((action) => /* @__PURE__ */ react.createElement(_elementor_ui.MenuItem, {
1433 key: action.name,
1434 onClick: (e) => {
1435 e.stopPropagation();
1436 action.onClick?.(itemId);
1437 menuState.close();
1438 },
1439 sx: {
1440 color: action.color,
1441 gap: 1
1442 }
1443 }, action.icon && (0, react.createElement)(action.icon, { fontSize: "inherit" }), " ", action.name))));
1444 };
1445
1446 //#endregion
1447 //#region packages/packages/core/editor-variables/src/components/variables-manager/ui/variable-table-row.tsx
1448 var TRACKING_DATA = {
1449 target_name: "variables_manager",
1450 target_location: "variables_manager"
1451 };
1452 var VariableRow = (props) => {
1453 const { row, variables, handleOnChange, autoEditVariableId, onAutoEditComplete, onFieldError, menuActions, handleRowRef, itemProps, showDropIndication, triggerProps, itemStyle, triggerStyle, isDragged, dropPosition, setTriggerRef, isSorting } = props;
1454 const promotionRef = (0, react.useRef)(null);
1455 const isDisabled = !useQuotaPermissions(row.type).canEdit();
1456 const showIndicationBefore = showDropIndication && dropPosition === "before";
1457 const showIndicationAfter = showDropIndication && dropPosition === "after";
1458 return /* @__PURE__ */ react.createElement(_elementor_ui.TableRow, {
1459 ...itemProps,
1460 ref: itemProps.ref,
1461 selected: isDragged,
1462 sx: {
1463 ...isDisabled && { "& td, & th": { color: "text.disabled" } },
1464 ...showIndicationBefore && { "& td, & th": {
1465 borderTop: "2px solid",
1466 borderTopColor: "primary.main"
1467 } },
1468 ...showIndicationAfter && { "& td, & th": {
1469 borderBottom: "2px solid",
1470 borderBottomColor: "primary.main"
1471 } },
1472 "&:hover, &:focus-within": {
1473 backgroundColor: "action.hover",
1474 "& [role=\"toolbar\"], & [draggable]": { opacity: 1 }
1475 },
1476 "& [role=\"toolbar\"], & [draggable]": { opacity: 0 }
1477 },
1478 style: {
1479 ...itemStyle,
1480 ...triggerStyle
1481 },
1482 onClick: () => {
1483 if (isDisabled) promotionRef.current?.toggle();
1484 }
1485 }, /* @__PURE__ */ react.createElement(VariableTableCell, {
1486 noPadding: true,
1487 width: 10,
1488 maxWidth: 10
1489 }, /* @__PURE__ */ react.createElement(_elementor_ui.IconButton, {
1490 size: "small",
1491 ref: setTriggerRef,
1492 ...triggerProps,
1493 disabled: isSorting,
1494 draggable: true
1495 }, /* @__PURE__ */ react.createElement(_elementor_icons.GripVerticalIcon, { fontSize: "inherit" }))), /* @__PURE__ */ react.createElement(VariableTableCell, null, /* @__PURE__ */ react.createElement(VariableEditableCell, {
1496 initialValue: row.name,
1497 onChange: (value) => {
1498 if (value !== row.name && !isDisabled) handleOnChange({
1499 ...variables,
1500 [row.id]: {
1501 ...variables[row.id],
1502 label: value
1503 }
1504 });
1505 },
1506 prefixElement: (0, react.createElement)(row.icon, {
1507 fontSize: "inherit",
1508 color: isDisabled ? "disabled" : "inherit"
1509 }),
1510 editableElement: ({ value, onChange, onValidationChange, error }) => /* @__PURE__ */ react.createElement(LabelField, {
1511 id: "variable-label-" + row.id,
1512 size: "tiny",
1513 value,
1514 onChange,
1515 onErrorChange: (errorMsg) => {
1516 onValidationChange?.(errorMsg);
1517 onFieldError?.(!!errorMsg);
1518 },
1519 error,
1520 focusOnShow: true,
1521 selectOnShow: autoEditVariableId === row.id,
1522 showWarningInfotip: true,
1523 variables
1524 }),
1525 autoEdit: autoEditVariableId === row.id && !isDisabled,
1526 onRowRef: handleRowRef(row.id),
1527 onAutoEditComplete: autoEditVariableId === row.id ? onAutoEditComplete : void 0,
1528 fieldType: "label",
1529 disabled: isDisabled
1530 }, /* @__PURE__ */ react.createElement(_elementor_editor_ui.EllipsisWithTooltip, {
1531 title: row.name,
1532 sx: { border: "4px solid transparent" }
1533 }, row.name))), /* @__PURE__ */ react.createElement(VariableTableCell, null, /* @__PURE__ */ react.createElement(VariableEditableCell, {
1534 initialValue: row.value,
1535 onChange: (value) => {
1536 if (value !== row.value && !isDisabled) handleOnChange({
1537 ...variables,
1538 [row.id]: {
1539 ...variables[row.id],
1540 value
1541 }
1542 });
1543 },
1544 editableElement: ({ value, onChange, onValidationChange, error }) => row.valueField?.({
1545 value,
1546 onChange,
1547 onPropTypeKeyChange: (type) => {
1548 if (!isDisabled && type !== row.type) handleOnChange({
1549 ...variables,
1550 [row.id]: {
1551 ...variables[row.id],
1552 type
1553 }
1554 });
1555 },
1556 propTypeKey: row.type,
1557 onValidationChange: (errorMsg) => {
1558 onValidationChange?.(errorMsg);
1559 onFieldError?.(!!errorMsg);
1560 },
1561 error
1562 }) ?? /* @__PURE__ */ react.createElement(react.Fragment, null),
1563 onRowRef: handleRowRef(row.id),
1564 gap: .25,
1565 fieldType: "value",
1566 disabled: isDisabled
1567 }, row.startIcon && row.startIcon({ value: row.value }), /* @__PURE__ */ react.createElement(_elementor_editor_ui.EllipsisWithTooltip, {
1568 title: row.value,
1569 sx: {
1570 border: "4px solid transparent",
1571 lineHeight: "1",
1572 pt: .25
1573 }
1574 }, row.value))), /* @__PURE__ */ react.createElement(VariableTableCell, {
1575 align: "right",
1576 noPadding: true,
1577 width: 16,
1578 maxWidth: 16,
1579 sx: { paddingInlineEnd: 1 }
1580 }, /* @__PURE__ */ react.createElement(_elementor_ui.Stack, {
1581 role: "toolbar",
1582 direction: "row",
1583 justifyContent: "flex-end",
1584 alignItems: "center"
1585 }, isDisabled && /* @__PURE__ */ react.createElement(VariablePromotionChip, {
1586 variableType: row.variableType,
1587 upgradeUrl: `https://go.elementor.com/renew-license-manager-${row.variableType}-variable`,
1588 ref: promotionRef,
1589 trackingData: TRACKING_DATA
1590 }), /* @__PURE__ */ react.createElement(VariableEditMenu, {
1591 menuActions: menuActions(row.id),
1592 disabled: isSorting,
1593 itemId: row.id
1594 }))));
1595 };
1596
1597 //#endregion
1598 //#region packages/packages/core/editor-variables/src/components/variables-manager/variables-manager-table.tsx
1599 var VariablesManagerTable = ({ menuActions, variables, onChange: handleOnChange, autoEditVariableId, onAutoEditComplete, onFieldError }) => {
1600 const tableContainerRef = (0, react.useRef)(null);
1601 const variableRowRefs = (0, react.useRef)(/* @__PURE__ */ new Map());
1602 (0, react.useEffect)(() => {
1603 if (autoEditVariableId && tableContainerRef.current) {
1604 const rowElement = variableRowRefs.current.get(autoEditVariableId);
1605 if (rowElement) setTimeout(() => {
1606 rowElement.scrollIntoView({
1607 behavior: "smooth",
1608 block: "center",
1609 inline: "nearest"
1610 });
1611 }, 100);
1612 }
1613 }, [autoEditVariableId]);
1614 const handleRowRef = (id) => (ref) => {
1615 if (ref) variableRowRefs.current.set(id, ref);
1616 else variableRowRefs.current.delete(id);
1617 };
1618 const ids = Object.keys(variables).sort(sortVariablesOrder(variables));
1619 const rows = ids.map((id) => {
1620 const variable = variables[id];
1621 const variableType = getVariableType(variable.type);
1622 if (!variableType) return null;
1623 return {
1624 id,
1625 type: variable.type,
1626 name: variable.label,
1627 value: variable.value,
1628 ...variableType
1629 };
1630 }).filter(Boolean);
1631 const tableSX = {
1632 minWidth: 250,
1633 tableLayout: "fixed"
1634 };
1635 const handleReorder = (newIds) => {
1636 const updatedVariables = { ...variables };
1637 newIds.forEach((id, index) => {
1638 const current = updatedVariables[id];
1639 if (!current) return;
1640 updatedVariables[id] = Object.assign({}, current, { order: index + 1 });
1641 });
1642 handleOnChange(updatedVariables);
1643 };
1644 return /* @__PURE__ */ react.createElement(_elementor_ui.TableContainer, {
1645 ref: tableContainerRef,
1646 sx: { overflow: "initial" }
1647 }, /* @__PURE__ */ react.createElement(_elementor_ui.Table, {
1648 sx: tableSX,
1649 "aria-label": "Variables manager list with drag and drop reordering",
1650 stickyHeader: true
1651 }, /* @__PURE__ */ react.createElement(_elementor_ui.TableHead, null, /* @__PURE__ */ react.createElement(_elementor_ui.TableRow, null, /* @__PURE__ */ react.createElement(VariableTableCell, {
1652 isHeader: true,
1653 noPadding: true,
1654 width: 10,
1655 maxWidth: 10
1656 }), /* @__PURE__ */ react.createElement(VariableTableCell, { isHeader: true }, (0, _wordpress_i18n.__)("Name", "elementor")), /* @__PURE__ */ react.createElement(VariableTableCell, { isHeader: true }, (0, _wordpress_i18n.__)("Value", "elementor")), /* @__PURE__ */ react.createElement(VariableTableCell, {
1657 isHeader: true,
1658 noPadding: true,
1659 width: 16,
1660 maxWidth: 16
1661 }))), /* @__PURE__ */ react.createElement(_elementor_ui.TableBody, null, /* @__PURE__ */ react.createElement(_elementor_ui.UnstableSortableProvider, {
1662 value: ids,
1663 onChange: handleReorder,
1664 variant: "static",
1665 restrictAxis: true,
1666 dragOverlay: ({ children: dragOverlayChildren, ...dragOverlayProps }) => /* @__PURE__ */ react.createElement(_elementor_ui.Table, {
1667 sx: tableSX,
1668 ...dragOverlayProps
1669 }, /* @__PURE__ */ react.createElement(_elementor_ui.TableBody, null, dragOverlayChildren))
1670 }, rows.map((row) => /* @__PURE__ */ react.createElement(_elementor_ui.UnstableSortableItem, {
1671 key: row.id,
1672 id: row.id,
1673 render: (props) => /* @__PURE__ */ react.createElement(VariableRow, {
1674 ...props,
1675 row,
1676 variables,
1677 handleOnChange,
1678 autoEditVariableId,
1679 onAutoEditComplete,
1680 onFieldError,
1681 menuActions,
1682 handleRowRef
1683 })
1684 }))))));
1685 };
1686 function sortVariablesOrder(variables) {
1687 return (a, b) => {
1688 return (variables[a]?.order ?? Number.MAX_SAFE_INTEGER) - (variables[b]?.order ?? Number.MAX_SAFE_INTEGER);
1689 };
1690 }
1691
1692 //#endregion
1693 //#region packages/packages/core/editor-variables/src/components/variables-manager/variables-manager-panel.tsx
1694 var STOP_SYNC_MESSAGE_KEY = "stop-sync-variable";
1695 function VariablesManagerPanelEmbedded({ onRequestClose, onExposeCloseAttempt }) {
1696 return /* @__PURE__ */ react.createElement(VariablesManagerPanelContent, {
1697 onRequestClose,
1698 onExposeCloseAttempt
1699 });
1700 }
1701 function VariablesManagerPanelContent({ onRequestClose, onExposeCloseAttempt }) {
1702 const { open: openSaveChangesDialog, close: closeSaveChangesDialog, isOpen: isSaveChangesDialogOpen } = (0, _elementor_editor_ui.useDialog)();
1703 const [isStopSyncSuppressed] = (0, _elementor_editor_current_user.useSuppressedMessage)(STOP_SYNC_MESSAGE_KEY);
1704 const createMenuState = (0, _elementor_ui.usePopupState)({ variant: "popover" });
1705 const { variables, isDirty, searchValue, isSaveDisabled, handleOnChange, createVariable, duplicateVariable, handleDeleteVariable, handleStartSync: startSyncFromState, handleStopSync: stopSyncFromState, handleSave, isSaving, handleSearch, setIsSaving, setIsSaveDisabled } = useVariablesManagerState();
1706 const { autoEditVariableId, startAutoEdit, handleAutoEditComplete } = useAutoEdit();
1707 const { createNavigationCallback, resetNavigation } = useErrorNavigation();
1708 const [deleteConfirmation, setDeleteConfirmation] = (0, react.useState)(null);
1709 const [stopSyncConfirmation, setStopSyncConfirmation] = (0, react.useState)(null);
1710 const [serverError, setServerError] = (0, react.useState)(null);
1711 usePreventUnload(isDirty);
1712 const handleClosePanel = (0, react.useCallback)(() => {
1713 if (isDirty) {
1714 openSaveChangesDialog();
1715 return;
1716 }
1717 onRequestClose();
1718 }, [
1719 isDirty,
1720 openSaveChangesDialog,
1721 onRequestClose
1722 ]);
1723 (0, react.useEffect)(() => {
1724 if (!onExposeCloseAttempt) return;
1725 onExposeCloseAttempt(() => handleClosePanel());
1726 return () => onExposeCloseAttempt(null);
1727 }, [onExposeCloseAttempt, handleClosePanel]);
1728 const handleCreateVariable = (0, react.useCallback)((type, defaultName, defaultValue) => {
1729 const newId = createVariable(type, defaultName, defaultValue);
1730 if (newId) startAutoEdit(newId);
1731 }, [createVariable, startAutoEdit]);
1732 const handleSaveClick = async () => {
1733 try {
1734 setServerError(null);
1735 resetNavigation();
1736 const result = await handleSave();
1737 trackVariablesManagerEvent({ action: "saveChanges" });
1738 return result;
1739 } catch (error) {
1740 const mappedError = mapServerError(error);
1741 const duplicatedIds = mappedError?.action?.data?.duplicatedIds;
1742 if (mappedError && "label" === mappedError.field) {
1743 if (duplicatedIds && mappedError.action) mappedError.action.callback = createNavigationCallback(duplicatedIds, startAutoEdit, () => {
1744 setIsSaveDisabled(false);
1745 });
1746 setServerError(mappedError);
1747 setIsSaveDisabled(true);
1748 resetNavigation();
1749 }
1750 return {
1751 success: false,
1752 error: mappedError
1753 };
1754 } finally {
1755 setIsSaving(false);
1756 }
1757 };
1758 const handleDeleteVariableWithConfirmation = (0, react.useCallback)((itemId) => {
1759 handleDeleteVariable(itemId);
1760 setDeleteConfirmation(null);
1761 }, [handleDeleteVariable]);
1762 const commitStopSync = (0, react.useCallback)((itemId) => {
1763 stopSyncFromState(itemId);
1764 const variable = variables[itemId];
1765 if (variable) trackVariableSyncToV3({
1766 variableLabel: variable.label,
1767 action: "unsync"
1768 });
1769 }, [stopSyncFromState, variables]);
1770 const handleStartSync = (0, react.useCallback)((itemId) => {
1771 startSyncFromState(itemId);
1772 const variable = variables[itemId];
1773 if (variable) trackVariableSyncToV3({
1774 variableLabel: variable.label,
1775 action: "sync"
1776 });
1777 }, [startSyncFromState, variables]);
1778 const handleStopSync = (0, react.useCallback)((itemId) => {
1779 if (!isStopSyncSuppressed) setStopSyncConfirmation(itemId);
1780 else commitStopSync(itemId);
1781 }, [isStopSyncSuppressed, commitStopSync]);
1782 const buildMenuActions = (0, react.useCallback)((variableId) => {
1783 const variable = variables[variableId];
1784 if (!variable) return [];
1785 const typeActions = getMenuActionsForVariable(variable.type, {
1786 variable,
1787 variableId,
1788 handlers: {
1789 onStartSync: handleStartSync,
1790 onStopSync: handleStopSync
1791 }
1792 });
1793 const duplicateAction = {
1794 name: (0, _wordpress_i18n.__)("Duplicate", "elementor"),
1795 icon: _elementor_icons.CopyIcon,
1796 color: "text.primary",
1797 onClick: (itemId) => {
1798 const newId = duplicateVariable(itemId);
1799 startAutoEdit(newId);
1800 trackVariablesManagerEvent({
1801 action: "duplicate",
1802 varType: getVariableType(variable.type)?.variableType
1803 });
1804 }
1805 };
1806 const deleteAction = {
1807 name: (0, _wordpress_i18n.__)("Delete", "elementor"),
1808 icon: _elementor_icons.TrashIcon,
1809 color: "error.main",
1810 onClick: (itemId) => {
1811 const v = variables[itemId];
1812 if (v) {
1813 setDeleteConfirmation({
1814 id: itemId,
1815 label: v.label
1816 });
1817 trackVariablesManagerEvent({
1818 action: "delete",
1819 varType: getVariableType(v.type)?.variableType
1820 });
1821 }
1822 }
1823 };
1824 return [
1825 ...typeActions,
1826 duplicateAction,
1827 deleteAction
1828 ];
1829 }, [
1830 variables,
1831 handleStartSync,
1832 handleStopSync,
1833 duplicateVariable,
1834 startAutoEdit
1835 ]);
1836 const hasVariables = Object.keys(variables).length > 0;
1837 return /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement(_elementor_ui.Stack, {
1838 direction: "column",
1839 sx: {
1840 height: "100%",
1841 width: "100%",
1842 flex: 1,
1843 minHeight: 0,
1844 overflow: "hidden"
1845 }
1846 }, /* @__PURE__ */ react.createElement(_elementor_ui.Stack, {
1847 direction: "row",
1848 alignItems: "center",
1849 spacing: 1,
1850 width: "100%",
1851 sx: {
1852 flexShrink: 0,
1853 px: 2,
1854 pb: 1
1855 }
1856 }, /* @__PURE__ */ react.createElement(_elementor_editor_ui.SearchField, {
1857 placeholder: (0, _wordpress_i18n.__)("Search", "elementor"),
1858 value: searchValue,
1859 onSearch: handleSearch,
1860 sx: {
1861 flex: 1,
1862 minWidth: 0,
1863 px: 0,
1864 py: 0,
1865 display: "flex",
1866 alignItems: "center",
1867 alignSelf: "stretch"
1868 }
1869 }), /* @__PURE__ */ react.createElement(_elementor_ui.Box, { sx: {
1870 display: "flex",
1871 flexShrink: 0,
1872 alignItems: "center"
1873 } }, /* @__PURE__ */ react.createElement(VariableManagerCreateMenu, {
1874 outlinedTrigger: true,
1875 onCreate: handleCreateVariable,
1876 variables,
1877 menuState: createMenuState
1878 }))), /* @__PURE__ */ react.createElement(_elementor_ui.Divider, { sx: { width: "100%" } }), /* @__PURE__ */ react.createElement(_elementor_editor_panels.PanelBody, { sx: {
1879 display: "flex",
1880 flexDirection: "column",
1881 flex: 1,
1882 minHeight: 0
1883 } }, hasVariables && /* @__PURE__ */ react.createElement(VariablesManagerTable, {
1884 menuActions: buildMenuActions,
1885 variables,
1886 onChange: handleOnChange,
1887 autoEditVariableId,
1888 onAutoEditComplete: handleAutoEditComplete,
1889 onFieldError: setIsSaveDisabled
1890 }), !hasVariables && searchValue && /* @__PURE__ */ react.createElement(NoSearchResults, {
1891 searchValue,
1892 onClear: () => handleSearch(""),
1893 icon: /* @__PURE__ */ react.createElement(_elementor_icons.ColorFilterIcon, { fontSize: "large" })
1894 }), !hasVariables && !searchValue && /* @__PURE__ */ react.createElement(EmptyState, {
1895 title: (0, _wordpress_i18n.__)("Create your first variable", "elementor"),
1896 message: (0, _wordpress_i18n.__)("Variables are saved attributes that you can apply anywhere on your site.", "elementor"),
1897 icon: /* @__PURE__ */ react.createElement(_elementor_icons.ColorFilterIcon, { fontSize: "large" }),
1898 onAdd: createMenuState.open
1899 })), /* @__PURE__ */ react.createElement(_elementor_editor_panels.PanelFooter, null, /* @__PURE__ */ react.createElement(_elementor_ui.Infotip, {
1900 placement: "right",
1901 open: !!serverError,
1902 content: serverError ? /* @__PURE__ */ react.createElement(_elementor_ui.Alert, {
1903 severity: serverError.severity ?? "error",
1904 action: serverError.action?.label ? /* @__PURE__ */ react.createElement(_elementor_ui.AlertAction, { onClick: serverError.action.callback }, serverError.action.label) : void 0,
1905 onClose: !serverError.action?.label ? () => {
1906 setServerError(null);
1907 setIsSaveDisabled(false);
1908 } : void 0,
1909 icon: serverError.IconComponent ? /* @__PURE__ */ react.createElement(serverError.IconComponent, null) : /* @__PURE__ */ react.createElement(_elementor_icons.AlertTriangleFilledIcon, null)
1910 }, /* @__PURE__ */ react.createElement(_elementor_ui.AlertTitle, null, serverError.message), serverError.action?.message) : null,
1911 arrow: false,
1912 slotProps: { popper: { modifiers: [{
1913 name: "offset",
1914 options: { offset: [-10, 10] }
1915 }] } }
1916 }, /* @__PURE__ */ react.createElement(_elementor_ui.Button, {
1917 fullWidth: true,
1918 size: "small",
1919 color: "global",
1920 variant: "contained",
1921 disabled: isSaveDisabled || !isDirty || isSaving,
1922 onClick: handleSaveClick,
1923 loading: isSaving
1924 }, (0, _wordpress_i18n.__)("Save changes", "elementor"))))), deleteConfirmation && /* @__PURE__ */ react.createElement(DeleteConfirmationDialog, {
1925 open: true,
1926 label: deleteConfirmation.label,
1927 onConfirm: () => handleDeleteVariableWithConfirmation(deleteConfirmation.id),
1928 closeDialog: () => setDeleteConfirmation(null)
1929 }), stopSyncConfirmation && /* @__PURE__ */ react.createElement(StopSyncConfirmationDialog, {
1930 open: true,
1931 onClose: () => setStopSyncConfirmation(null),
1932 onConfirm: () => {
1933 commitStopSync(stopSyncConfirmation);
1934 setStopSyncConfirmation(null);
1935 }
1936 }), isSaveChangesDialogOpen && /* @__PURE__ */ react.createElement(_elementor_editor_ui.SaveChangesDialog, null, /* @__PURE__ */ react.createElement(_elementor_editor_ui.SaveChangesDialog.Title, { onClose: closeSaveChangesDialog }, (0, _wordpress_i18n.__)("You have unsaved changes", "elementor")), /* @__PURE__ */ react.createElement(_elementor_editor_ui.SaveChangesDialog.Content, null, /* @__PURE__ */ react.createElement(_elementor_editor_ui.SaveChangesDialog.ContentText, null, (0, _wordpress_i18n.__)("You have unsaved changes in the Variables Manager.", "elementor")), /* @__PURE__ */ react.createElement(_elementor_editor_ui.SaveChangesDialog.ContentText, null, (0, _wordpress_i18n.__)("To avoid losing your updates, save your changes before leaving.", "elementor"))), /* @__PURE__ */ react.createElement(_elementor_editor_ui.SaveChangesDialog.Actions, { actions: {
1937 discard: {
1938 label: (0, _wordpress_i18n.__)("Discard", "elementor"),
1939 action: () => {
1940 closeSaveChangesDialog();
1941 onRequestClose();
1942 }
1943 },
1944 confirm: {
1945 label: (0, _wordpress_i18n.__)("Save", "elementor"),
1946 action: async () => {
1947 const result = await handleSaveClick();
1948 closeSaveChangesDialog();
1949 if (result?.success) onRequestClose();
1950 }
1951 }
1952 } })));
1953 }
1954 var usePreventUnload = (isDirty) => {
1955 (0, react.useEffect)(() => {
1956 const handleBeforeUnload = (event) => {
1957 if (isDirty) event.preventDefault();
1958 };
1959 window.addEventListener("beforeunload", handleBeforeUnload);
1960 return () => {
1961 window.removeEventListener("beforeunload", handleBeforeUnload);
1962 };
1963 }, [isDirty]);
1964 };
1965 var StopSyncConfirmationDialog = ({ open, onClose, onConfirm }) => {
1966 const [, suppressStopSyncMessage] = (0, _elementor_editor_current_user.useSuppressedMessage)(STOP_SYNC_MESSAGE_KEY);
1967 return /* @__PURE__ */ react.createElement(_elementor_editor_ui.ConfirmationDialog, {
1968 open,
1969 onClose
1970 }, /* @__PURE__ */ react.createElement(_elementor_editor_ui.ConfirmationDialog.Title, {
1971 icon: _elementor_icons.ColorFilterIcon,
1972 iconColor: "primary"
1973 }, (0, _wordpress_i18n.__)("Stop syncing variable color", "elementor")), /* @__PURE__ */ react.createElement(_elementor_editor_ui.ConfirmationDialog.Content, null, /* @__PURE__ */ react.createElement(_elementor_editor_ui.ConfirmationDialog.ContentText, null, (0, _wordpress_i18n.__)("This will disconnect the variable color from Global Colors. Existing uses on your site will automatically switch to a default color.", "elementor"))), /* @__PURE__ */ react.createElement(_elementor_editor_ui.ConfirmationDialog.Actions, {
1974 onClose,
1975 onConfirm,
1976 cancelLabel: (0, _wordpress_i18n.__)("Cancel", "elementor"),
1977 confirmLabel: (0, _wordpress_i18n.__)("Got it", "elementor"),
1978 color: "primary",
1979 onSuppressMessage: suppressStopSyncMessage,
1980 suppressLabel: (0, _wordpress_i18n.__)("Don't show again", "elementor")
1981 }));
1982 };
1983
1984 //#endregion
1985 //#region packages/packages/core/editor-variables/src/components/global-styles-import-listener.tsx
1986 function GlobalStylesImportListener() {
1987 (0, react.useEffect)(() => {
1988 const handleGlobalStylesImported = () => {
1989 service.load();
1990 };
1991 window.addEventListener(_elementor_editor_canvas.GLOBAL_STYLES_IMPORTED_EVENT, handleGlobalStylesImported);
1992 return () => {
1993 window.removeEventListener(_elementor_editor_canvas.GLOBAL_STYLES_IMPORTED_EVENT, handleGlobalStylesImported);
1994 };
1995 }, []);
1996 return null;
1997 }
1998
1999 //#endregion
2000 //#region packages/packages/core/editor-variables/src/utils/extract-variables-from-style-value.ts
2001 var VARIABLE_TYPE_KEYS = [
2002 "global-color-variable",
2003 "global-font-variable",
2004 "global-size-variable",
2005 "global-custom-size-variable"
2006 ];
2007 function tryExtractVariable(value) {
2008 for (const key of VARIABLE_TYPE_KEYS) {
2009 const propUtil = (0, _elementor_editor_props.getPropSchemaFromCache)(key);
2010 if (propUtil?.isValid(value)) return {
2011 type: key,
2012 variableId: propUtil.extract(value)
2013 };
2014 }
2015 return null;
2016 }
2017 function traverse(value, path, result) {
2018 const extracted = tryExtractVariable(value);
2019 if (extracted) {
2020 result.push({
2021 ...extracted,
2022 controlPath: path.join(".")
2023 });
2024 return;
2025 }
2026 if ((0, _elementor_editor_props.isTransformable)(value)) {
2027 traverse(value.value, path, result);
2028 return;
2029 }
2030 if (value && typeof value === "object") for (const [key, val] of Object.entries(value)) traverse(val, [...path, key], result);
2031 }
2032 function extractVariablesFromStyleValue(styleValue) {
2033 const result = [];
2034 traverse(styleValue, [], result);
2035 return result;
2036 }
2037
2038 //#endregion
2039 //#region packages/packages/core/editor-variables/src/components/mcp-variable-connect-listener.tsx
2040 function McpVariableConnectListener() {
2041 (0, react.useEffect)(() => {
2042 const handleMcpStylesApplied = (event) => {
2043 const { styleValue } = event.detail;
2044 extractVariablesFromStyleValue(styleValue).forEach(({ type, controlPath }) => {
2045 trackVariableEvent({
2046 varType: type,
2047 controlPath,
2048 action: "connect",
2049 executedBy: "mcp_tool"
2050 });
2051 });
2052 };
2053 window.addEventListener(_elementor_editor_mcp.MCP_STYLES_APPLIED_EVENT, handleMcpStylesApplied);
2054 return () => {
2055 window.removeEventListener(_elementor_editor_mcp.MCP_STYLES_APPLIED_EVENT, handleMcpStylesApplied);
2056 };
2057 }, []);
2058 return null;
2059 }
2060
2061 //#endregion
2062 //#region packages/packages/core/editor-variables/src/utils/unlink-variable.ts
2063 function transformValueBeforeUnlink(variable, propTypeKey) {
2064 const { valueTransformer } = getVariableType(propTypeKey);
2065 if (valueTransformer) return valueTransformer(variable.value, variable.type);
2066 return variable.value;
2067 }
2068 function createUnlinkHandler(variable, propTypeKey, setValue) {
2069 return () => {
2070 const { fallbackPropTypeUtil } = getVariableType(propTypeKey);
2071 const transformedValue = transformValueBeforeUnlink(variable, propTypeKey);
2072 setValue(fallbackPropTypeUtil.create(transformedValue));
2073 };
2074 }
2075
2076 //#endregion
2077 //#region packages/packages/core/editor-variables/src/context/variable-selection-popover.context.tsx
2078 var PopoverContentRefContext = (0, react.createContext)(null);
2079 var PopoverContentRefContextProvider = ({ children }) => {
2080 const [anchorRef, setAnchorRef] = (0, react.useState)(null);
2081 return /* @__PURE__ */ react.createElement(PopoverContentRefContext.Provider, { value: anchorRef }, /* @__PURE__ */ react.createElement(_elementor_ui.Box, { ref: setAnchorRef }, children));
2082 };
2083 var usePopoverContentRef = () => {
2084 return (0, react.useContext)(PopoverContentRefContext);
2085 };
2086
2087 //#endregion
2088 //#region packages/packages/core/editor-variables/src/hooks/use-initial-value.ts
2089 var useInitialValue = () => {
2090 const { value: initial } = (0, _elementor_editor_controls.useBoundProp)();
2091 const hasAssignedVariable = hasVariableType(initial?.$$type) && Boolean(initial?.value);
2092 const variable = useVariable(hasAssignedVariable ? initial.value : "");
2093 if (hasAssignedVariable) return variable ? variable.value : "";
2094 return initial?.value ?? "";
2095 };
2096
2097 //#endregion
2098 //#region packages/packages/core/editor-variables/src/hooks/use-variable-bound-prop.ts
2099 var useVariableBoundProp = () => {
2100 const { propTypeUtil } = useVariableType();
2101 const boundProp = (0, _elementor_editor_controls.useBoundProp)(propTypeUtil);
2102 return {
2103 ...boundProp,
2104 setVariableValue: (value) => resolveBoundPropAndSetValue(value, boundProp),
2105 variableId: boundProp.value ?? boundProp.placeholder
2106 };
2107 };
2108 var resolveBoundPropAndSetValue = (value, boundProp) => {
2109 const propValue = unwrapValue(boundProp.value);
2110 const placeholder = unwrapValue(boundProp.placeholder);
2111 const newValue = unwrapValue(value);
2112 if (!propValue && placeholder === newValue) return boundProp.setValue(null);
2113 return boundProp.setValue(value);
2114 };
2115 var unwrapValue = (input) => {
2116 if ((0, _elementor_editor_props.isTransformable)(input)) return input.value;
2117 return input;
2118 };
2119
2120 //#endregion
2121 //#region packages/packages/core/editor-variables/src/components/ui/form-field.tsx
2122 var FormField = ({ id, label, errorMsg, noticeMsg, children }) => {
2123 return /* @__PURE__ */ react.createElement(_elementor_ui.Grid, {
2124 container: true,
2125 gap: .75,
2126 alignItems: "center"
2127 }, /* @__PURE__ */ react.createElement(_elementor_ui.Grid, {
2128 item: true,
2129 xs: 12
2130 }, /* @__PURE__ */ react.createElement(_elementor_ui.FormLabel, {
2131 htmlFor: id,
2132 size: "tiny"
2133 }, label)), /* @__PURE__ */ react.createElement(_elementor_ui.Grid, {
2134 item: true,
2135 xs: 12
2136 }, children, errorMsg && /* @__PURE__ */ react.createElement(_elementor_ui.FormHelperText, { error: true }, errorMsg), noticeMsg && /* @__PURE__ */ react.createElement(_elementor_ui.FormHelperText, null, noticeMsg)));
2137 };
2138
2139 //#endregion
2140 //#region packages/packages/core/editor-variables/src/components/variable-creation.tsx
2141 var SIZE$5 = "tiny";
2142 var VariableCreation = ({ onGoBack, onClose }) => {
2143 const { icon: VariableIcon, valueField: ValueField, propTypeUtil } = useVariableType();
2144 const { setVariableValue: setVariable, path } = useVariableBoundProp();
2145 const { propType } = (0, _elementor_editor_controls.useBoundProp)();
2146 const [value, setValue] = (0, react.useState)(useInitialValue());
2147 const [label, setLabel] = (0, react.useState)("");
2148 const [errorMessage, setErrorMessage] = (0, react.useState)("");
2149 const [valueFieldError, setValueFieldError] = (0, react.useState)("");
2150 const [propTypeKey, setPropTypeKey] = (0, react.useState)(propTypeUtil.key);
2151 const { labelFieldError, setLabelFieldError } = useLabelError();
2152 const resetFields = () => {
2153 setValue("");
2154 setLabel("");
2155 setErrorMessage("");
2156 setValueFieldError("");
2157 };
2158 const closePopover = () => {
2159 resetFields();
2160 onClose();
2161 };
2162 const handleCreateAndTrack = () => {
2163 createVariable({
2164 value,
2165 label,
2166 type: propTypeKey
2167 }, { eventData: { controlPath: path.join(".") } }).then((key) => {
2168 setVariable(key);
2169 closePopover();
2170 }).catch((error) => {
2171 const mappedError = mapServerError(error);
2172 if (mappedError && "label" === mappedError.field) {
2173 setLabel("");
2174 setLabelFieldError({
2175 value: label,
2176 message: mappedError.message
2177 });
2178 return;
2179 }
2180 setErrorMessage(ERROR_MESSAGES.UNEXPECTED_ERROR);
2181 });
2182 };
2183 const hasEmptyFields = () => {
2184 if ("" === label.trim()) return true;
2185 if ("string" === typeof value) return "" === value.trim();
2186 return false === Boolean(value);
2187 };
2188 const hasErrors = () => {
2189 return !!errorMessage;
2190 };
2191 const isSubmitDisabled = hasEmptyFields() || hasErrors();
2192 const handleKeyDown = (event) => {
2193 if (event.key === "Enter" && !isSubmitDisabled) {
2194 event.preventDefault();
2195 handleCreateAndTrack();
2196 }
2197 };
2198 return /* @__PURE__ */ react.createElement(_elementor_editor_ui.SectionPopoverBody, { height: "auto" }, /* @__PURE__ */ react.createElement(_elementor_editor_ui.PopoverHeader, {
2199 icon: /* @__PURE__ */ react.createElement(react.Fragment, null, onGoBack && /* @__PURE__ */ react.createElement(_elementor_ui.IconButton, {
2200 size: SIZE$5,
2201 "aria-label": (0, _wordpress_i18n.__)("Go Back", "elementor"),
2202 onClick: onGoBack
2203 }, /* @__PURE__ */ react.createElement(_elementor_icons.ArrowLeftIcon, { fontSize: SIZE$5 })), /* @__PURE__ */ react.createElement(VariableIcon, { fontSize: SIZE$5 })),
2204 title: (0, _wordpress_i18n.__)("Create variable", "elementor"),
2205 onClose: closePopover
2206 }), /* @__PURE__ */ react.createElement(_elementor_ui.Divider, null), /* @__PURE__ */ react.createElement(_elementor_editor_controls.PopoverContent, { p: 2 }, /* @__PURE__ */ react.createElement(FormField, {
2207 id: "variable-label",
2208 label: (0, _wordpress_i18n.__)("Name", "elementor"),
2209 errorMsg: labelFieldError?.message,
2210 noticeMsg: labelHint(label)
2211 }, /* @__PURE__ */ react.createElement(LabelField, {
2212 id: "variable-label",
2213 value: label,
2214 error: labelFieldError,
2215 onChange: (newValue) => {
2216 setLabel(newValue);
2217 setErrorMessage("");
2218 },
2219 onErrorChange: (errorMsg) => {
2220 setLabelFieldError({
2221 value: "",
2222 message: errorMsg
2223 });
2224 },
2225 onKeyDown: handleKeyDown,
2226 focusOnShow: true
2227 })), ValueField && /* @__PURE__ */ react.createElement(FormField, {
2228 errorMsg: valueFieldError,
2229 label: (0, _wordpress_i18n.__)("Value", "elementor")
2230 }, /* @__PURE__ */ react.createElement(_elementor_ui.Typography, {
2231 variant: "h5",
2232 id: "variable-value-wrapper"
2233 }, /* @__PURE__ */ react.createElement(ValueField, {
2234 value,
2235 onPropTypeKeyChange: (key) => setPropTypeKey(key),
2236 onChange: (newValue) => {
2237 setValue(newValue);
2238 setErrorMessage("");
2239 setValueFieldError("");
2240 },
2241 onValidationChange: setValueFieldError,
2242 propType,
2243 onKeyDown: handleKeyDown
2244 }))), errorMessage && /* @__PURE__ */ react.createElement(_elementor_ui.FormHelperText, { error: true }, errorMessage)), /* @__PURE__ */ react.createElement(_elementor_ui.CardActions, { sx: {
2245 pt: .5,
2246 pb: 1
2247 } }, /* @__PURE__ */ react.createElement(_elementor_ui.Button, {
2248 id: "create-variable-button",
2249 size: "small",
2250 variant: "contained",
2251 disabled: isSubmitDisabled,
2252 onClick: handleCreateAndTrack
2253 }, (0, _wordpress_i18n.__)("Create", "elementor"))));
2254 };
2255
2256 //#endregion
2257 //#region packages/packages/core/editor-variables/src/components/ui/edit-confirmation-dialog.tsx
2258 var EDIT_CONFIRMATION_DIALOG_ID = "edit-confirmation-dialog";
2259 var EditConfirmationDialog = ({ closeDialog, onConfirm, onSuppressMessage }) => {
2260 const [dontShowAgain, setDontShowAgain] = (0, react.useState)(false);
2261 const handleSave = () => {
2262 if (dontShowAgain) onSuppressMessage?.();
2263 onConfirm?.();
2264 };
2265 return /* @__PURE__ */ react.createElement(_elementor_ui.Dialog, {
2266 open: true,
2267 onClose: closeDialog,
2268 maxWidth: "xs"
2269 }, /* @__PURE__ */ react.createElement(_elementor_ui.DialogTitle, {
2270 display: "flex",
2271 alignItems: "center",
2272 gap: 1
2273 }, /* @__PURE__ */ react.createElement(_elementor_icons.AlertTriangleFilledIcon, { color: "secondary" }), (0, _wordpress_i18n.__)("Changes to variables go live right away.", "elementor")), /* @__PURE__ */ react.createElement(_elementor_ui.DialogContent, null, /* @__PURE__ */ react.createElement(_elementor_ui.DialogContentText, {
2274 variant: "body2",
2275 color: "textPrimary"
2276 }, (0, _wordpress_i18n.__)("Don't worry - all other changes you make will wait until you publish your site.", "elementor"))), /* @__PURE__ */ react.createElement(_elementor_ui.DialogActions, { sx: {
2277 justifyContent: "space-between",
2278 alignItems: "center"
2279 } }, /* @__PURE__ */ react.createElement(_elementor_ui.FormControlLabel, {
2280 control: /* @__PURE__ */ react.createElement(_elementor_ui.Checkbox, {
2281 checked: dontShowAgain,
2282 onChange: (event) => setDontShowAgain(event.target.checked),
2283 size: "small"
2284 }),
2285 label: /* @__PURE__ */ react.createElement(_elementor_ui.Typography, { variant: "body2" }, (0, _wordpress_i18n.__)("Don't show me again", "elementor"))
2286 }), /* @__PURE__ */ react.createElement("div", null, /* @__PURE__ */ react.createElement(_elementor_ui.Button, {
2287 color: "secondary",
2288 onClick: closeDialog
2289 }, (0, _wordpress_i18n.__)("Keep editing", "elementor")), /* @__PURE__ */ react.createElement(_elementor_ui.Button, {
2290 variant: "contained",
2291 color: "secondary",
2292 onClick: handleSave,
2293 sx: { ml: 1 }
2294 }, (0, _wordpress_i18n.__)("Save", "elementor")))));
2295 };
2296
2297 //#endregion
2298 //#region packages/packages/core/editor-variables/src/components/variable-edit.tsx
2299 var SIZE$4 = "tiny";
2300 var DELETE_LABEL = (0, _wordpress_i18n.__)("Delete variable", "elementor");
2301 var VariableEdit = ({ onClose, onGoBack, onSubmit, editId }) => {
2302 const { icon: VariableIcon, valueField: ValueField, variableType, propTypeUtil } = useVariableType();
2303 const { setVariableValue: notifyBoundPropChange, variableId, path } = useVariableBoundProp();
2304 const { propType } = (0, _elementor_editor_controls.useBoundProp)();
2305 const [isMessageSuppressed, suppressMessage] = (0, _elementor_editor_current_user.useSuppressedMessage)(EDIT_CONFIRMATION_DIALOG_ID);
2306 const [deleteConfirmation, setDeleteConfirmation] = (0, react.useState)(false);
2307 const [editConfirmation, setEditConfirmation] = (0, react.useState)(false);
2308 const [errorMessage, setErrorMessage] = (0, react.useState)("");
2309 const [valueFieldError, setValueFieldError] = (0, react.useState)("");
2310 const { labelFieldError, setLabelFieldError } = useLabelError();
2311 const variable = useVariable(editId);
2312 const [propTypeKey, setPropTypeKey] = (0, react.useState)(variable?.type ?? propTypeUtil.key);
2313 if (!variable) throw new Error(`Global ${variableType} variable not found`);
2314 const userPermissions = usePermissions();
2315 const [value, setValue] = (0, react.useState)(() => variable.value);
2316 const [label, setLabel] = (0, react.useState)(() => variable.label);
2317 (0, react.useEffect)(() => {
2318 styleVariablesRepository.update({ [editId]: {
2319 ...variable,
2320 value
2321 } });
2322 return () => {
2323 styleVariablesRepository.update({ [editId]: { ...variable } });
2324 };
2325 }, [
2326 editId,
2327 value,
2328 variable
2329 ]);
2330 const handleUpdate = () => {
2331 if (isMessageSuppressed) handleSaveVariable();
2332 else setEditConfirmation(true);
2333 };
2334 const handleSaveVariable = () => {
2335 updateVariable(editId, propTypeKey !== variable.type ? {
2336 value,
2337 label,
2338 type: propTypeKey
2339 } : {
2340 value,
2341 label
2342 }, { eventData: { controlPath: path.join(".") } }).then(() => {
2343 maybeTriggerBoundPropChange();
2344 onSubmit?.();
2345 }).catch((error) => {
2346 const mappedError = mapServerError(error);
2347 if (mappedError && "label" === mappedError.field) {
2348 setLabel("");
2349 setLabelFieldError({
2350 value: label,
2351 message: mappedError.message
2352 });
2353 return;
2354 }
2355 setErrorMessage(ERROR_MESSAGES.UNEXPECTED_ERROR);
2356 });
2357 };
2358 const handleDelete = () => {
2359 deleteVariable(editId).then(() => {
2360 maybeTriggerBoundPropChange();
2361 onSubmit?.();
2362 });
2363 };
2364 const maybeTriggerBoundPropChange = () => {
2365 if (editId === variableId) notifyBoundPropChange(editId);
2366 };
2367 const handleDeleteConfirmation = () => {
2368 setDeleteConfirmation(true);
2369 };
2370 const closeDeleteDialog = () => () => {
2371 setDeleteConfirmation(false);
2372 };
2373 const closeEditDialog = () => () => {
2374 setEditConfirmation(false);
2375 };
2376 const actions = [];
2377 if (userPermissions.canDelete()) actions.push(/* @__PURE__ */ react.createElement(_elementor_ui.Tooltip, {
2378 key: "delete",
2379 placement: "top",
2380 title: DELETE_LABEL
2381 }, /* @__PURE__ */ react.createElement(_elementor_ui.IconButton, {
2382 size: SIZE$4,
2383 onClick: handleDeleteConfirmation,
2384 "aria-label": DELETE_LABEL
2385 }, /* @__PURE__ */ react.createElement(_elementor_icons.TrashIcon, { fontSize: SIZE$4 }))));
2386 const hasEmptyFields = () => {
2387 if ("" === label.trim()) return true;
2388 if ("string" === typeof value) return "" === value.trim();
2389 return false === Boolean(value);
2390 };
2391 const noValueChanged = () => {
2392 return value === variable.value && label === variable.label;
2393 };
2394 const hasErrors = () => {
2395 return !!errorMessage;
2396 };
2397 const isSubmitDisabled = noValueChanged() || hasEmptyFields() || hasErrors();
2398 const handleKeyDown = (event) => {
2399 if (event.key === "Enter" && !isSubmitDisabled) {
2400 event.preventDefault();
2401 handleUpdate();
2402 }
2403 };
2404 return /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement(_elementor_editor_ui.SectionPopoverBody, { height: "auto" }, /* @__PURE__ */ react.createElement(_elementor_editor_ui.PopoverHeader, {
2405 title: (0, _wordpress_i18n.__)("Edit variable", "elementor"),
2406 onClose,
2407 icon: /* @__PURE__ */ react.createElement(react.Fragment, null, onGoBack && /* @__PURE__ */ react.createElement(_elementor_ui.IconButton, {
2408 size: SIZE$4,
2409 "aria-label": (0, _wordpress_i18n.__)("Go Back", "elementor"),
2410 onClick: onGoBack
2411 }, /* @__PURE__ */ react.createElement(_elementor_icons.ArrowLeftIcon, { fontSize: SIZE$4 })), /* @__PURE__ */ react.createElement(VariableIcon, { fontSize: SIZE$4 })),
2412 actions
2413 }), /* @__PURE__ */ react.createElement(_elementor_ui.Divider, null), /* @__PURE__ */ react.createElement(_elementor_editor_controls.PopoverContent, { p: 2 }, /* @__PURE__ */ react.createElement(FormField, {
2414 id: "variable-label",
2415 label: (0, _wordpress_i18n.__)("Name", "elementor"),
2416 errorMsg: labelFieldError?.message,
2417 noticeMsg: labelHint(label)
2418 }, /* @__PURE__ */ react.createElement(LabelField, {
2419 id: "variable-label",
2420 value: label,
2421 error: labelFieldError,
2422 onChange: (newValue) => {
2423 setLabel(newValue);
2424 setErrorMessage("");
2425 },
2426 onErrorChange: (errorMsg) => {
2427 setLabelFieldError({
2428 value: "",
2429 message: errorMsg
2430 });
2431 },
2432 onKeyDown: handleKeyDown,
2433 focusOnShow: true
2434 })), ValueField && /* @__PURE__ */ react.createElement(FormField, {
2435 errorMsg: valueFieldError,
2436 label: (0, _wordpress_i18n.__)("Value", "elementor")
2437 }, /* @__PURE__ */ react.createElement(_elementor_ui.Typography, { variant: "h5" }, /* @__PURE__ */ react.createElement(ValueField, {
2438 propTypeKey: variable.type,
2439 onPropTypeKeyChange: (key) => setPropTypeKey(key),
2440 value,
2441 onChange: (newValue) => {
2442 setValue(newValue);
2443 setErrorMessage("");
2444 setValueFieldError("");
2445 },
2446 onKeyDown: handleKeyDown,
2447 onValidationChange: setValueFieldError,
2448 propType
2449 }))), errorMessage && /* @__PURE__ */ react.createElement(_elementor_ui.FormHelperText, { error: true }, errorMessage)), /* @__PURE__ */ react.createElement(_elementor_ui.CardActions, { sx: {
2450 pt: .5,
2451 pb: 1
2452 } }, /* @__PURE__ */ react.createElement(_elementor_ui.Button, {
2453 size: "small",
2454 variant: "contained",
2455 disabled: isSubmitDisabled,
2456 onClick: handleUpdate
2457 }, (0, _wordpress_i18n.__)("Save", "elementor")))), deleteConfirmation && /* @__PURE__ */ react.createElement(DeleteConfirmationDialog, {
2458 open: true,
2459 label,
2460 onConfirm: handleDelete,
2461 closeDialog: closeDeleteDialog()
2462 }), editConfirmation && !isMessageSuppressed && /* @__PURE__ */ react.createElement(EditConfirmationDialog, {
2463 closeDialog: closeEditDialog(),
2464 onConfirm: handleSaveVariable,
2465 onSuppressMessage: suppressMessage
2466 }));
2467 };
2468
2469 //#endregion
2470 //#region packages/packages/core/editor-variables/src/components/ui/menu-item-content.tsx
2471 var SIZE$3 = "tiny";
2472 var EDIT_LABEL = (0, _wordpress_i18n.__)("Edit variable", "elementor");
2473 var MenuItemContent = ({ item, disabled = false }) => {
2474 const onEdit = item.onEdit;
2475 return /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement(_elementor_ui.ListItemIcon, { sx: { color: disabled ? "text.disabled" : "inherit" } }, item.icon), /* @__PURE__ */ react.createElement(_elementor_ui.Box, { sx: {
2476 flex: 1,
2477 minWidth: 0,
2478 display: "flex",
2479 alignItems: "center",
2480 gap: 1
2481 } }, /* @__PURE__ */ react.createElement(_elementor_editor_ui.EllipsisWithTooltip, {
2482 title: item.label || item.value,
2483 as: _elementor_ui.Typography,
2484 variant: "caption",
2485 color: disabled ? "text.disabled" : "text.primary",
2486 sx: {
2487 marginTop: "1px",
2488 lineHeight: "2"
2489 },
2490 maxWidth: "50%"
2491 }), item.secondaryText && /* @__PURE__ */ react.createElement(_elementor_editor_ui.EllipsisWithTooltip, {
2492 title: item.secondaryText,
2493 as: _elementor_ui.Typography,
2494 variant: "caption",
2495 color: disabled ? "text.disabled" : "text.tertiary",
2496 sx: {
2497 marginTop: "1px",
2498 lineHeight: "1"
2499 },
2500 maxWidth: "50%"
2501 })), !!onEdit && !disabled && /* @__PURE__ */ react.createElement(_elementor_ui.Tooltip, {
2502 placement: "top",
2503 title: EDIT_LABEL
2504 }, /* @__PURE__ */ react.createElement(_elementor_ui.IconButton, {
2505 sx: {
2506 mx: 1,
2507 opacity: "0"
2508 },
2509 onClick: (e) => {
2510 e.stopPropagation();
2511 onEdit(item.value);
2512 },
2513 "aria-label": EDIT_LABEL
2514 }, /* @__PURE__ */ react.createElement(_elementor_icons.EditIcon, {
2515 color: "action",
2516 fontSize: SIZE$3
2517 }))));
2518 };
2519
2520 //#endregion
2521 //#region packages/packages/core/editor-variables/src/components/ui/styled-menu-list.tsx
2522 var VariablesStyledMenuList = (0, _elementor_ui.styled)(_elementor_ui.MenuList)(({ theme, disabled }) => ({
2523 "& > li": {
2524 height: 32,
2525 width: "100%",
2526 display: "flex",
2527 alignItems: "center"
2528 },
2529 "& > [role=\"option\"]": {
2530 ...theme.typography.caption,
2531 lineHeight: "inherit",
2532 padding: theme.spacing(.5, 1, .5, 2),
2533 ...!disabled && {
2534 "&:hover, &:focus": { backgroundColor: theme.palette.action.hover },
2535 cursor: "pointer"
2536 },
2537 "&[aria-selected=\"true\"]": { backgroundColor: theme.palette.action.selected },
2538 textOverflow: "ellipsis",
2539 position: "absolute",
2540 top: 0,
2541 left: 0,
2542 "&:hover .MuiIconButton-root, .MuiIconButton-root:focus": { opacity: 1 }
2543 },
2544 width: "100%",
2545 position: "relative"
2546 }));
2547
2548 //#endregion
2549 //#region packages/packages/core/editor-variables/src/components/variables-selection.tsx
2550 var SIZE$2 = "tiny";
2551 var CREATE_LABEL = (0, _wordpress_i18n.__)("Create variable", "elementor");
2552 var MANAGER_LABEL = (0, _wordpress_i18n.__)("Variables Manager", "elementor");
2553 var getProUpgradeUrl = (variableType) => `https://go.elementor.com/renew-license-panel-${variableType}-variable`;
2554 var VariablesSelection = ({ closePopover, onAdd, onEdit, onSettings, disabled = false }) => {
2555 const { icon: VariableIcon, startIcon, variableType, propTypeUtil, emptyState } = useVariableType();
2556 const { value: variable, setValue: setVariable, path } = useVariableBoundProp();
2557 const [searchValue, setSearchValue] = (0, react.useState)("");
2558 const { list: variables, hasMatches: hasSearchResults, isSourceNotEmpty: hasVariables, hasNoCompatibleVariables } = useFilteredVariables(searchValue, propTypeUtil.key);
2559 const handleSetVariable = (key) => {
2560 setVariable(key);
2561 trackVariableEvent({
2562 varType: variableType,
2563 controlPath: path.join("."),
2564 action: "connect"
2565 });
2566 closePopover();
2567 };
2568 const onAddAndTrack = () => {
2569 onAdd?.();
2570 trackVariableEvent({
2571 varType: variableType,
2572 controlPath: path.join("."),
2573 action: "add"
2574 });
2575 };
2576 const actions = [];
2577 if (onAdd) actions.push(/* @__PURE__ */ react.createElement(_elementor_ui.Tooltip, {
2578 key: "add",
2579 placement: "top",
2580 title: CREATE_LABEL
2581 }, /* @__PURE__ */ react.createElement("span", null, /* @__PURE__ */ react.createElement(_elementor_ui.IconButton, {
2582 id: "add-variable-button",
2583 size: SIZE$2,
2584 onClick: onAddAndTrack,
2585 "aria-label": CREATE_LABEL,
2586 disabled
2587 }, /* @__PURE__ */ react.createElement(_elementor_icons.PlusIcon, { fontSize: SIZE$2 })))));
2588 if (onSettings) {
2589 const handleOpenManager = () => {
2590 onSettings();
2591 trackVariablesManagerEvent({
2592 action: "openManager",
2593 source: "vars-popover",
2594 varType: variableType,
2595 controlPath: path.join(".")
2596 });
2597 };
2598 actions.push(/* @__PURE__ */ react.createElement(_elementor_ui.Tooltip, {
2599 key: "settings",
2600 placement: "top",
2601 title: MANAGER_LABEL
2602 }, /* @__PURE__ */ react.createElement(_elementor_ui.IconButton, {
2603 id: "variables-manager-button",
2604 size: SIZE$2,
2605 onClick: handleOpenManager,
2606 "aria-label": MANAGER_LABEL
2607 }, /* @__PURE__ */ react.createElement(_elementor_icons.SettingsIcon, { fontSize: SIZE$2 }))));
2608 }
2609 const StartIcon = startIcon || (() => /* @__PURE__ */ react.createElement(VariableIcon, { fontSize: SIZE$2 }));
2610 const items = variables.map(({ value, label, key }) => ({
2611 type: "item",
2612 value: key,
2613 label,
2614 icon: /* @__PURE__ */ react.createElement(StartIcon, { value }),
2615 secondaryText: value,
2616 onEdit: onEdit ? () => onEdit?.(key) : void 0
2617 }));
2618 const handleSearch = (search) => {
2619 setSearchValue(search);
2620 };
2621 const handleClearSearch = () => {
2622 setSearchValue("");
2623 };
2624 (0, react.useEffect)(() => {
2625 if (disabled) (0, _elementor_editor_controls.trackViewPromotion)({
2626 target_name: "variables_popover",
2627 target_location: "widget_panel",
2628 location_l1: "variables_list"
2629 });
2630 }, [disabled]);
2631 return /* @__PURE__ */ react.createElement(_elementor_editor_ui.SectionPopoverBody, null, /* @__PURE__ */ react.createElement(_elementor_editor_ui.PopoverHeader, {
2632 title: (0, _wordpress_i18n.__)("Variables", "elementor"),
2633 icon: /* @__PURE__ */ react.createElement(_elementor_icons.ColorFilterIcon, { fontSize: SIZE$2 }),
2634 onClose: closePopover,
2635 actions
2636 }), hasVariables && /* @__PURE__ */ react.createElement(_elementor_editor_ui.SearchField, {
2637 value: searchValue,
2638 onSearch: handleSearch,
2639 placeholder: (0, _wordpress_i18n.__)("Search", "elementor")
2640 }), /* @__PURE__ */ react.createElement(_elementor_ui.Divider, null), hasVariables && hasSearchResults && /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement(_elementor_editor_ui.PopoverMenuList, {
2641 items,
2642 onSelect: disabled ? () => {} : handleSetVariable,
2643 onClose: () => {},
2644 selectedValue: variable,
2645 "data-testid": `${variableType}-variables-list`,
2646 menuListTemplate: (props) => /* @__PURE__ */ react.createElement(VariablesStyledMenuList, {
2647 ...props,
2648 disabled
2649 }),
2650 menuItemContentTemplate: (item) => /* @__PURE__ */ react.createElement(MenuItemContent, {
2651 item,
2652 disabled
2653 })
2654 }), disabled && /* @__PURE__ */ react.createElement(_elementor_editor_ui.PromotionAlert, {
2655 message: (0, _wordpress_i18n.sprintf)((0, _wordpress_i18n.__)("Upgrade to continue creating and editing %s variables.", "elementor"), variableType),
2656 upgradeUrl: getProUpgradeUrl(variableType),
2657 onCtaClick: () => (0, _elementor_editor_controls.trackUpgradePromotionClick)({
2658 target_name: "variables_popover",
2659 location_l1: "variables_list"
2660 })
2661 })), !hasSearchResults && hasVariables && /* @__PURE__ */ react.createElement(NoSearchResults, {
2662 searchValue,
2663 onClear: handleClearSearch,
2664 icon: /* @__PURE__ */ react.createElement(VariableIcon, { fontSize: "large" })
2665 }), disabled && !hasVariables && /* @__PURE__ */ react.createElement(EmptyState, {
2666 title: (0, _wordpress_i18n.sprintf)((0, _wordpress_i18n.__)("No %s variables yet", "elementor"), variableType),
2667 message: (0, _wordpress_i18n.sprintf)((0, _wordpress_i18n.__)("Upgrade to create %s variables and maintain consistent element sizing.", "elementor"), variableType),
2668 icon: /* @__PURE__ */ react.createElement(VariableIcon, { fontSize: "large" })
2669 }, emptyState), !hasVariables && !hasNoCompatibleVariables && !disabled && /* @__PURE__ */ react.createElement(EmptyState, {
2670 title: (0, _wordpress_i18n.sprintf)((0, _wordpress_i18n.__)("Create your first %s variable", "elementor"), variableType),
2671 message: (0, _wordpress_i18n.__)("Variables are saved attributes that you can apply anywhere on your site.", "elementor"),
2672 icon: /* @__PURE__ */ react.createElement(VariableIcon, { fontSize: "large" }),
2673 onAdd
2674 }), hasNoCompatibleVariables && !disabled && /* @__PURE__ */ react.createElement(EmptyState, {
2675 title: (0, _wordpress_i18n.__)("No compatible variables", "elementor"),
2676 message: (0, _wordpress_i18n.__)("Looks like none of your variables work with this control. Create a new variable to use it here.", "elementor"),
2677 icon: /* @__PURE__ */ react.createElement(VariableIcon, { fontSize: "large" }),
2678 onAdd
2679 }));
2680 };
2681
2682 //#endregion
2683 //#region packages/packages/core/editor-variables/src/components/variable-selection-popover.tsx
2684 var VIEW_LIST = "list";
2685 var VIEW_ADD = "add";
2686 var VIEW_EDIT = "edit";
2687 var VariableSelectionPopover = ({ closePopover, propTypeKey, selectedVariable }) => {
2688 const [currentView, setCurrentView] = (0, react.useState)(VIEW_LIST);
2689 const [editId, setEditId] = (0, react.useState)("");
2690 const onSettingsAvailable = () => {
2691 window.dispatchEvent(new CustomEvent("elementor/toggle-design-system", { detail: { tab: "variables" } }));
2692 };
2693 return /* @__PURE__ */ react.createElement(VariableTypeProvider, { propTypeKey }, /* @__PURE__ */ react.createElement(PopoverContentRefContextProvider, null, RenderView({
2694 propTypeKey,
2695 currentView,
2696 selectedVariable,
2697 editId,
2698 setEditId,
2699 setCurrentView,
2700 closePopover,
2701 onSettings: onSettingsAvailable
2702 })));
2703 };
2704 function RenderView(props) {
2705 const userPermissions = usePermissions();
2706 const userQuotaPermissions = useQuotaPermissions(props.propTypeKey);
2707 const handlers = {
2708 onClose: () => {
2709 props.closePopover();
2710 },
2711 onGoBack: () => {
2712 props.setCurrentView(VIEW_LIST);
2713 }
2714 };
2715 if (userPermissions.canAdd()) handlers.onAdd = () => {
2716 props.setCurrentView(VIEW_ADD);
2717 };
2718 if (userPermissions.canEdit()) handlers.onEdit = (key) => {
2719 props.setEditId(key);
2720 props.setCurrentView(VIEW_EDIT);
2721 };
2722 if (userPermissions.canManageSettings() && props.onSettings) handlers.onSettings = () => {
2723 props.closePopover();
2724 props.onSettings?.();
2725 };
2726 const handleSubmitOnEdit = () => {
2727 if (props?.selectedVariable?.key === props.editId) handlers.onClose();
2728 else handlers.onGoBack?.();
2729 };
2730 if (VIEW_LIST === props.currentView) return /* @__PURE__ */ react.createElement(VariablesSelection, {
2731 closePopover: handlers.onClose,
2732 onAdd: handlers.onAdd,
2733 onEdit: handlers.onEdit,
2734 onSettings: handlers.onSettings,
2735 disabled: !userQuotaPermissions.canAdd()
2736 });
2737 if (VIEW_ADD === props.currentView) return /* @__PURE__ */ react.createElement(VariableCreation, {
2738 onGoBack: handlers.onGoBack,
2739 onClose: handlers.onClose
2740 });
2741 if (VIEW_EDIT === props.currentView) return /* @__PURE__ */ react.createElement(VariableEdit, {
2742 editId: props.editId,
2743 onGoBack: handlers.onGoBack,
2744 onClose: handlers.onClose,
2745 onSubmit: handleSubmitOnEdit
2746 });
2747 return null;
2748 }
2749
2750 //#endregion
2751 //#region packages/packages/core/editor-variables/src/components/ui/tags/assigned-tag.tsx
2752 var SIZE$1 = "tiny";
2753 var UNLINK_LABEL = (0, _wordpress_i18n.__)("Unlink variable", "elementor");
2754 var AssignedTag = ({ startIcon, label, onUnlink, ...props }) => {
2755 const actions = [];
2756 if (onUnlink) actions.push(/* @__PURE__ */ react.createElement(_elementor_ui.Tooltip, {
2757 key: "unlink",
2758 title: UNLINK_LABEL,
2759 placement: "bottom"
2760 }, /* @__PURE__ */ react.createElement(_elementor_ui.IconButton, {
2761 size: SIZE$1,
2762 onClick: onUnlink,
2763 "aria-label": UNLINK_LABEL
2764 }, /* @__PURE__ */ react.createElement(_elementor_icons.DetachIcon, { fontSize: SIZE$1 }))));
2765 return /* @__PURE__ */ react.createElement(_elementor_ui.Tooltip, {
2766 title: label,
2767 placement: "top"
2768 }, /* @__PURE__ */ react.createElement(_elementor_ui.UnstableTag, {
2769 fullWidth: true,
2770 showActionsOnHover: true,
2771 startIcon: /* @__PURE__ */ react.createElement(_elementor_ui.Stack, {
2772 gap: .5,
2773 direction: "row",
2774 alignItems: "center"
2775 }, startIcon),
2776 label: /* @__PURE__ */ react.createElement(_elementor_ui.Box, { sx: {
2777 display: "inline-grid",
2778 minWidth: 0
2779 } }, /* @__PURE__ */ react.createElement(_elementor_ui.Typography, {
2780 sx: { lineHeight: 1.34 },
2781 variant: "caption",
2782 noWrap: true
2783 }, label)),
2784 actions,
2785 ...props
2786 }));
2787 };
2788
2789 //#endregion
2790 //#region packages/packages/core/editor-variables/src/components/ui/variable/assigned-variable.tsx
2791 var AssignedVariable = ({ variable, propTypeKey }) => {
2792 const { startIcon, propTypeUtil } = getVariableType(propTypeKey);
2793 const { setValue } = (0, _elementor_editor_controls.useBoundProp)();
2794 const anchorRef = (0, react.useRef)(null);
2795 const popupState = (0, _elementor_ui.usePopupState)({
2796 variant: "popover",
2797 popupId: `elementor-variables-list-${(0, react.useId)()}`
2798 });
2799 const unlinkVariable = createUnlinkHandler(variable, propTypeKey, setValue);
2800 const StartIcon = startIcon || (() => null);
2801 return /* @__PURE__ */ react.createElement(_elementor_ui.Box, { ref: anchorRef }, /* @__PURE__ */ react.createElement(AssignedTag, {
2802 label: variable.label,
2803 startIcon: /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement(_elementor_icons.ColorFilterIcon, { fontSize: SIZE$1 }), /* @__PURE__ */ react.createElement(StartIcon, { value: variable.value })),
2804 onUnlink: unlinkVariable,
2805 ...(0, _elementor_ui.bindTrigger)(popupState)
2806 }), /* @__PURE__ */ react.createElement(_elementor_ui.Popover, {
2807 disableScrollLock: true,
2808 anchorEl: anchorRef.current,
2809 anchorOrigin: {
2810 vertical: "bottom",
2811 horizontal: "right"
2812 },
2813 transformOrigin: {
2814 vertical: "top",
2815 horizontal: "right"
2816 },
2817 PaperProps: { sx: { my: 1 } },
2818 ...(0, _elementor_ui.bindPopover)(popupState)
2819 }, /* @__PURE__ */ react.createElement(VariableSelectionPopover, {
2820 selectedVariable: variable,
2821 closePopover: popupState.close,
2822 propTypeKey: propTypeUtil.key
2823 })));
2824 };
2825
2826 //#endregion
2827 //#region packages/packages/core/editor-variables/src/components/variable-restore.tsx
2828 var SIZE = "tiny";
2829 var VariableRestore = ({ variableId, onClose, onSubmit }) => {
2830 const { icon: VariableIcon, valueField: ValueField, variableType, propTypeUtil } = useVariableType();
2831 const { setVariableValue: notifyBoundPropChange } = useVariableBoundProp();
2832 const { propType } = (0, _elementor_editor_controls.useBoundProp)();
2833 const variable = useVariable(variableId);
2834 if (!variable) throw new Error(`Global ${variableType} variable not found`);
2835 const [errorMessage, setErrorMessage] = (0, react.useState)("");
2836 const [valueFieldError, setValueFieldError] = (0, react.useState)("");
2837 const [label, setLabel] = (0, react.useState)(variable.label);
2838 const [value, setValue] = (0, react.useState)(variable.value);
2839 const [propTypeKey, setPropTypeKey] = (0, react.useState)(variable?.type ?? propTypeUtil.key);
2840 const { labelFieldError, setLabelFieldError } = useLabelError({
2841 value: variable.label,
2842 message: ERROR_MESSAGES.DUPLICATED_LABEL
2843 });
2844 const handleRestore = () => {
2845 (propTypeKey !== variable.type ? restoreVariable(variableId, label, value, propTypeKey) : restoreVariable(variableId, label, value)).then(() => {
2846 notifyBoundPropChange(variableId);
2847 onSubmit?.();
2848 }).catch((error) => {
2849 const mappedError = mapServerError(error);
2850 if (mappedError && "label" === mappedError.field) {
2851 setLabel("");
2852 setLabelFieldError({
2853 value: label,
2854 message: mappedError.message
2855 });
2856 return;
2857 }
2858 setErrorMessage(ERROR_MESSAGES.UNEXPECTED_ERROR);
2859 });
2860 };
2861 const hasEmptyFields = () => {
2862 if ("" === label.trim()) return true;
2863 if ("string" === typeof value) return "" === value.trim();
2864 return false === Boolean(value);
2865 };
2866 const noValueChanged = () => {
2867 return value === variable.value && label === variable.label;
2868 };
2869 const hasErrors = () => {
2870 return !!errorMessage;
2871 };
2872 const isSubmitDisabled = noValueChanged() || hasEmptyFields() || hasErrors();
2873 const handleKeyDown = (event) => {
2874 if (event.key === "Enter" && !isSubmitDisabled) {
2875 event.preventDefault();
2876 handleRestore();
2877 }
2878 };
2879 return /* @__PURE__ */ react.createElement(PopoverContentRefContextProvider, null, /* @__PURE__ */ react.createElement(_elementor_editor_ui.SectionPopoverBody, { height: "auto" }, /* @__PURE__ */ react.createElement(_elementor_editor_ui.PopoverHeader, {
2880 icon: /* @__PURE__ */ react.createElement(VariableIcon, { fontSize: SIZE }),
2881 title: (0, _wordpress_i18n.__)("Restore variable", "elementor"),
2882 onClose
2883 }), /* @__PURE__ */ react.createElement(_elementor_ui.Divider, null), /* @__PURE__ */ react.createElement(_elementor_editor_controls.PopoverContent, { p: 2 }, /* @__PURE__ */ react.createElement(FormField, {
2884 id: "variable-label",
2885 label: (0, _wordpress_i18n.__)("Name", "elementor"),
2886 errorMsg: labelFieldError?.message,
2887 noticeMsg: labelHint(label)
2888 }, /* @__PURE__ */ react.createElement(LabelField, {
2889 id: "variable-label",
2890 value: label,
2891 error: labelFieldError,
2892 onChange: (newValue) => {
2893 setLabel(newValue);
2894 setErrorMessage("");
2895 },
2896 onErrorChange: (errorMsg) => {
2897 setLabelFieldError({
2898 value: "",
2899 message: errorMsg
2900 });
2901 },
2902 onKeyDown: handleKeyDown,
2903 focusOnShow: true
2904 })), ValueField && /* @__PURE__ */ react.createElement(FormField, {
2905 errorMsg: valueFieldError,
2906 label: (0, _wordpress_i18n.__)("Value", "elementor")
2907 }, /* @__PURE__ */ react.createElement(_elementor_ui.Typography, { variant: "h5" }, /* @__PURE__ */ react.createElement(ValueField, {
2908 propTypeKey,
2909 onPropTypeKeyChange: (key) => setPropTypeKey(key),
2910 value,
2911 onChange: (newValue) => {
2912 setValue(newValue);
2913 setErrorMessage("");
2914 setValueFieldError("");
2915 },
2916 onValidationChange: setValueFieldError,
2917 propType,
2918 onKeyDown: handleKeyDown
2919 }))), errorMessage && /* @__PURE__ */ react.createElement(_elementor_ui.FormHelperText, { error: true }, errorMessage)), /* @__PURE__ */ react.createElement(_elementor_ui.CardActions, { sx: {
2920 pt: .5,
2921 pb: 1
2922 } }, /* @__PURE__ */ react.createElement(_elementor_ui.Button, {
2923 size: "small",
2924 variant: "contained",
2925 disabled: isSubmitDisabled,
2926 onClick: handleRestore
2927 }, (0, _wordpress_i18n.__)("Restore", "elementor")))));
2928 };
2929
2930 //#endregion
2931 //#region packages/packages/core/editor-variables/src/components/ui/deleted-variable-alert.tsx
2932 var DeletedVariableAlert = ({ onClose, onUnlink, onRestore, label }) => {
2933 return /* @__PURE__ */ react.createElement(_elementor_ui.ClickAwayListener, { onClickAway: onClose }, /* @__PURE__ */ react.createElement(_elementor_ui.Alert, {
2934 variant: "standard",
2935 severity: "warning",
2936 onClose,
2937 action: /* @__PURE__ */ react.createElement(react.Fragment, null, onUnlink && /* @__PURE__ */ react.createElement(_elementor_ui.AlertAction, {
2938 variant: "contained",
2939 onClick: onUnlink
2940 }, (0, _wordpress_i18n.__)("Unlink", "elementor")), onRestore && /* @__PURE__ */ react.createElement(_elementor_ui.AlertAction, {
2941 variant: "outlined",
2942 onClick: onRestore
2943 }, (0, _wordpress_i18n.__)("Restore", "elementor"))),
2944 sx: { maxWidth: 300 }
2945 }, /* @__PURE__ */ react.createElement(_elementor_ui.AlertTitle, null, (0, _wordpress_i18n.__)("Deleted variable", "elementor")), /* @__PURE__ */ react.createElement(_elementor_ui.Typography, {
2946 variant: "body2",
2947 color: "textPrimary"
2948 }, (0, _wordpress_i18n.__)("The variable", "elementor"), "\xA0'", /* @__PURE__ */ react.createElement(_elementor_ui.Typography, {
2949 variant: "body2",
2950 component: "span",
2951 sx: { lineBreak: "anywhere" }
2952 }, label), "'\xA0", (0, _wordpress_i18n.__)("has been deleted, but it is still referenced in this location. You may restore the variable or unlink it to assign a different value.", "elementor"))));
2953 };
2954
2955 //#endregion
2956 //#region packages/packages/core/editor-variables/src/components/ui/tags/warning-variable-tag.tsx
2957 var WarningVariableTag = react.forwardRef(({ label, suffix, onClick, icon, ...props }, ref) => {
2958 const displayText = suffix ? `${label} (${suffix})` : label;
2959 return /* @__PURE__ */ react.createElement(_elementor_ui.Chip, {
2960 ref,
2961 size: "tiny",
2962 color: "warning",
2963 shape: "rounded",
2964 variant: "standard",
2965 onClick,
2966 icon: /* @__PURE__ */ react.createElement(_elementor_icons.AlertTriangleFilledIcon, null),
2967 label: /* @__PURE__ */ react.createElement(_elementor_ui.Tooltip, {
2968 title: displayText,
2969 placement: "top"
2970 }, /* @__PURE__ */ react.createElement(_elementor_ui.Box, { sx: {
2971 display: "inline-grid",
2972 minWidth: 0
2973 } }, /* @__PURE__ */ react.createElement(_elementor_ui.Typography, {
2974 variant: "caption",
2975 noWrap: true,
2976 sx: { lineHeight: 1.34 }
2977 }, displayText))),
2978 sx: {
2979 height: (theme) => theme.spacing(3.5),
2980 borderRadius: (theme) => theme.spacing(1),
2981 justifyContent: "flex-start",
2982 width: "100%"
2983 },
2984 ...props
2985 });
2986 });
2987 WarningVariableTag.displayName = "WarningVariableTag";
2988
2989 //#endregion
2990 //#region packages/packages/core/editor-variables/src/components/ui/variable/deleted-variable.tsx
2991 var DeletedVariable = ({ variable, propTypeKey }) => {
2992 const { propTypeUtil } = getVariableType(propTypeKey);
2993 const boundProp = (0, _elementor_editor_controls.useBoundProp)();
2994 const userPermissions = usePermissions();
2995 const [showInfotip, setShowInfotip] = (0, react.useState)(false);
2996 const toggleInfotip = () => setShowInfotip((prev) => !prev);
2997 const closeInfotip = () => setShowInfotip(false);
2998 const deletedChipAnchorRef = (0, react.useRef)(null);
2999 const popupState = (0, _elementor_ui.usePopupState)({
3000 variant: "popover",
3001 popupId: `elementor-variables-restore-${(0, react.useId)()}`
3002 });
3003 const handlers = {};
3004 if (userPermissions.canUnlink()) handlers.onUnlink = createUnlinkHandler(variable, propTypeKey, boundProp.setValue);
3005 if (userPermissions.canRestore()) handlers.onRestore = () => {
3006 if (!variable.key) return;
3007 restoreVariable(variable.key).then((id) => {
3008 resolveBoundPropAndSetValue(propTypeUtil.create(id), boundProp);
3009 closeInfotip();
3010 }).catch(() => {
3011 closeInfotip();
3012 popupState.setAnchorEl(deletedChipAnchorRef.current);
3013 popupState.open();
3014 });
3015 };
3016 const handleRestoreWithOverrides = () => {
3017 popupState.close();
3018 };
3019 return /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement(_elementor_ui.Box, { ref: deletedChipAnchorRef }, showInfotip && /* @__PURE__ */ react.createElement(_elementor_ui.Backdrop, {
3020 open: true,
3021 onClick: closeInfotip,
3022 invisible: true
3023 }), /* @__PURE__ */ react.createElement(_elementor_ui.Infotip, {
3024 color: "warning",
3025 placement: "right-start",
3026 open: showInfotip,
3027 disableHoverListener: true,
3028 onClose: closeInfotip,
3029 content: /* @__PURE__ */ react.createElement(DeletedVariableAlert, {
3030 onClose: closeInfotip,
3031 onUnlink: handlers.onUnlink,
3032 onRestore: handlers.onRestore,
3033 label: variable.label
3034 }),
3035 slotProps: { popper: { modifiers: [{
3036 name: "offset",
3037 options: { offset: [0, 24] }
3038 }] } }
3039 }, /* @__PURE__ */ react.createElement(WarningVariableTag, {
3040 label: variable.label,
3041 onClick: toggleInfotip,
3042 suffix: (0, _wordpress_i18n.__)("deleted", "elementor")
3043 })), /* @__PURE__ */ react.createElement(_elementor_ui.Popover, {
3044 disableScrollLock: true,
3045 anchorOrigin: {
3046 vertical: "bottom",
3047 horizontal: "right"
3048 },
3049 transformOrigin: {
3050 vertical: "top",
3051 horizontal: "right"
3052 },
3053 PaperProps: { sx: { my: 1 } },
3054 ...(0, _elementor_ui.bindPopover)(popupState)
3055 }, /* @__PURE__ */ react.createElement(VariableTypeProvider, { propTypeKey }, /* @__PURE__ */ react.createElement(VariableRestore, {
3056 variableId: variable.key ?? "",
3057 onClose: popupState.close,
3058 onSubmit: handleRestoreWithOverrides
3059 })))));
3060 };
3061
3062 //#endregion
3063 //#region packages/packages/core/editor-variables/src/components/ui/mismatch-variable-alert.tsx
3064 var i18n = {
3065 title: (0, _wordpress_i18n.__)("Variable has changed", "elementor"),
3066 message: (0, _wordpress_i18n.__)(`This variable is no longer compatible with this property. You can clear it or select a different one.`, "elementor"),
3067 buttons: {
3068 clear: (0, _wordpress_i18n.__)("Clear", "elementor"),
3069 select: (0, _wordpress_i18n.__)("Select variable", "elementor")
3070 }
3071 };
3072 var MismatchVariableAlert = ({ onClose, onClear, triggerSelect }) => {
3073 return /* @__PURE__ */ react.createElement(_elementor_ui.ClickAwayListener, { onClickAway: onClose }, /* @__PURE__ */ react.createElement(_elementor_ui.Alert, {
3074 variant: "standard",
3075 severity: "warning",
3076 onClose,
3077 action: /* @__PURE__ */ react.createElement(react.Fragment, null, onClear && /* @__PURE__ */ react.createElement(_elementor_ui.AlertAction, {
3078 variant: "contained",
3079 onClick: onClear
3080 }, i18n.buttons.clear), triggerSelect && /* @__PURE__ */ react.createElement(_elementor_ui.AlertAction, {
3081 variant: "outlined",
3082 onClick: triggerSelect
3083 }, i18n.buttons.select)),
3084 sx: { maxWidth: 300 }
3085 }, /* @__PURE__ */ react.createElement(_elementor_ui.AlertTitle, null, i18n.title), /* @__PURE__ */ react.createElement(_elementor_ui.Typography, {
3086 variant: "body2",
3087 color: "textPrimary"
3088 }, i18n.message)));
3089 };
3090
3091 //#endregion
3092 //#region packages/packages/core/editor-variables/src/components/ui/variable/mismatch-variable.tsx
3093 var MismatchVariable = ({ variable }) => {
3094 const { setValue, value } = (0, _elementor_editor_controls.useBoundProp)();
3095 const anchorRef = (0, react.useRef)(null);
3096 const popupState = (0, _elementor_ui.usePopupState)({
3097 variant: "popover",
3098 popupId: `elementor-variables-list-${(0, react.useId)()}`
3099 });
3100 const [infotipVisible, setInfotipVisible] = (0, react.useState)(false);
3101 const toggleInfotip = () => setInfotipVisible((prev) => !prev);
3102 const closeInfotip = () => setInfotipVisible(false);
3103 const triggerSelect = () => {
3104 closeInfotip();
3105 popupState.setAnchorEl(anchorRef.current);
3106 popupState.open();
3107 };
3108 const clearValue = () => {
3109 closeInfotip();
3110 setValue(null);
3111 };
3112 const showClearButton = !!value;
3113 return /* @__PURE__ */ react.createElement(_elementor_ui.Box, { ref: anchorRef }, infotipVisible && /* @__PURE__ */ react.createElement(_elementor_ui.Backdrop, {
3114 open: true,
3115 onClick: closeInfotip,
3116 invisible: true
3117 }), /* @__PURE__ */ react.createElement(_elementor_ui.Infotip, {
3118 color: "warning",
3119 placement: "right-start",
3120 open: infotipVisible,
3121 disableHoverListener: true,
3122 onClose: closeInfotip,
3123 content: /* @__PURE__ */ react.createElement(MismatchVariableAlert, {
3124 onClose: closeInfotip,
3125 onClear: showClearButton ? clearValue : void 0,
3126 triggerSelect
3127 }),
3128 slotProps: { popper: { modifiers: [{
3129 name: "offset",
3130 options: { offset: [0, 24] }
3131 }] } }
3132 }, /* @__PURE__ */ react.createElement(WarningVariableTag, {
3133 label: variable.label,
3134 onClick: toggleInfotip,
3135 suffix: (0, _wordpress_i18n.__)("changed", "elementor")
3136 })), /* @__PURE__ */ react.createElement(_elementor_ui.Popover, {
3137 disableScrollLock: true,
3138 anchorEl: anchorRef.current,
3139 anchorOrigin: {
3140 vertical: "bottom",
3141 horizontal: "right"
3142 },
3143 transformOrigin: {
3144 vertical: "top",
3145 horizontal: "right"
3146 },
3147 PaperProps: { sx: { my: 1 } },
3148 ...(0, _elementor_ui.bindPopover)(popupState)
3149 }, /* @__PURE__ */ react.createElement(VariableSelectionPopover, {
3150 selectedVariable: variable,
3151 closePopover: popupState.close,
3152 propTypeKey: variable.type
3153 })));
3154 };
3155
3156 //#endregion
3157 //#region packages/packages/core/editor-variables/src/components/ui/missing-variable-alert.tsx
3158 var MissingVariableAlert = ({ onClose, onClear }) => {
3159 return /* @__PURE__ */ react.createElement(_elementor_ui.ClickAwayListener, { onClickAway: onClose }, /* @__PURE__ */ react.createElement(_elementor_ui.Alert, {
3160 variant: "standard",
3161 severity: "warning",
3162 onClose,
3163 action: /* @__PURE__ */ react.createElement(react.Fragment, null, onClear && /* @__PURE__ */ react.createElement(_elementor_ui.AlertAction, {
3164 variant: "contained",
3165 onClick: onClear
3166 }, (0, _wordpress_i18n.__)("Clear", "elementor"))),
3167 sx: { maxWidth: 300 }
3168 }, /* @__PURE__ */ react.createElement(_elementor_ui.AlertTitle, null, (0, _wordpress_i18n.__)("This variable is missing", "elementor")), /* @__PURE__ */ react.createElement(_elementor_ui.Typography, {
3169 variant: "body2",
3170 color: "textPrimary"
3171 }, (0, _wordpress_i18n.__)("It may have been deleted. Try clearing this field and select a different value or variable.", "elementor"))));
3172 };
3173
3174 //#endregion
3175 //#region packages/packages/core/editor-variables/src/components/ui/variable/missing-variable.tsx
3176 var MissingVariable = () => {
3177 const { setValue } = (0, _elementor_editor_controls.useBoundProp)();
3178 const [infotipVisible, setInfotipVisible] = (0, react.useState)(false);
3179 const toggleInfotip = () => setInfotipVisible((prev) => !prev);
3180 const closeInfotip = () => setInfotipVisible(false);
3181 const clearValue = () => setValue(null);
3182 return /* @__PURE__ */ react.createElement(react.Fragment, null, infotipVisible && /* @__PURE__ */ react.createElement(_elementor_ui.Backdrop, {
3183 open: true,
3184 onClick: closeInfotip,
3185 invisible: true
3186 }), /* @__PURE__ */ react.createElement(_elementor_ui.Infotip, {
3187 color: "warning",
3188 placement: "right-start",
3189 open: infotipVisible,
3190 disableHoverListener: true,
3191 onClose: closeInfotip,
3192 content: /* @__PURE__ */ react.createElement(MissingVariableAlert, {
3193 onClose: closeInfotip,
3194 onClear: clearValue
3195 }),
3196 slotProps: { popper: { modifiers: [{
3197 name: "offset",
3198 options: { offset: [0, 24] }
3199 }] } }
3200 }, /* @__PURE__ */ react.createElement(WarningVariableTag, {
3201 label: (0, _wordpress_i18n.__)("Missing variable", "elementor"),
3202 onClick: toggleInfotip
3203 })));
3204 };
3205
3206 //#endregion
3207 //#region packages/packages/core/editor-variables/src/controls/variable-control.tsx
3208 var VariableControl = () => {
3209 const boundProp = (0, _elementor_editor_controls.useBoundProp)();
3210 const boundPropValue = boundProp.value ?? boundProp.placeholder;
3211 const assignedVariable = useVariable(boundPropValue?.value);
3212 if (!assignedVariable) return /* @__PURE__ */ react.createElement(MissingVariable, null);
3213 const { $$type: propTypeKey } = boundPropValue;
3214 if (assignedVariable?.deleted) return /* @__PURE__ */ react.createElement(DeletedVariable, {
3215 variable: assignedVariable,
3216 propTypeKey
3217 });
3218 const { isCompatible } = getVariableType(assignedVariable.type);
3219 if (isCompatible && !isCompatible(boundProp?.propType, assignedVariable)) return /* @__PURE__ */ react.createElement(MismatchVariable, { variable: assignedVariable });
3220 return /* @__PURE__ */ react.createElement(AssignedVariable, {
3221 variable: assignedVariable,
3222 propTypeKey
3223 });
3224 };
3225
3226 //#endregion
3227 //#region packages/packages/core/editor-variables/src/hooks/use-prop-variable-action.tsx
3228 var usePropVariableAction = () => {
3229 const { propType, path } = (0, _elementor_editor_controls.useBoundProp)();
3230 const variable = resolveVariableFromPropType(propType);
3231 return {
3232 visible: Boolean(variable),
3233 icon: _elementor_icons.ColorFilterIcon,
3234 title: (0, _wordpress_i18n.__)("Variables", "elementor"),
3235 content: ({ close: closePopover }) => {
3236 if (!variable) return null;
3237 trackOpenVariablePopover(path, variable.variableType);
3238 return /* @__PURE__ */ react.createElement(VariableSelectionPopover, {
3239 closePopover,
3240 propTypeKey: variable.propTypeUtil.key
3241 });
3242 }
3243 };
3244 };
3245 var resolveVariableFromPropType = (propType) => {
3246 if (propType.kind !== "union") return;
3247 for (const key of Object.keys(propType.prop_types)) {
3248 const variable = getVariableType(key);
3249 if (variable) return variable;
3250 }
3251 };
3252 var trackOpenVariablePopover = (path, variableType) => {
3253 trackVariableEvent({
3254 varType: variableType,
3255 controlPath: path.join("."),
3256 action: "open"
3257 });
3258 };
3259
3260 //#endregion
3261 //#region packages/packages/core/editor-variables/src/mcp/variable-tool-prompt.ts
3262 var MANAGE_VARIABLES_GUIDE_URI = "elementor://variables/tools/manage-global-variable-guide";
3263
3264 //#endregion
3265 //#region packages/packages/core/editor-variables/src/mcp/variables-resource.ts
3266 var MCP_PROXY_URL$1 = "elementor/v1/mcp-proxy";
3267 var GLOBAL_VARIABLES_URI = "elementor://global-variables";
3268 var initVariablesResource = (variablesMcpEntry, canvasMcpEntry) => {
3269 [canvasMcpEntry, variablesMcpEntry].forEach((entry) => {
3270 const { resource, sendResourceUpdated } = entry;
3271 const notifyGlobalVariablesUpdated = () => {
3272 sendResourceUpdated({ uri: GLOBAL_VARIABLES_URI });
3273 };
3274 resource("global-variables", GLOBAL_VARIABLES_URI, { description: "Global variables available (v4)" }, async (uri) => {
3275 const { data } = await (0, _elementor_http_client.httpService)().get(MCP_PROXY_URL$1, { params: { uri: uri.href } });
3276 return { contents: [{
3277 uri: uri.href,
3278 mimeType: "application/json",
3279 text: JSON.stringify(data.data ?? {})
3280 }] };
3281 });
3282 window.addEventListener(STORAGE_UPDATED_EVENT, notifyGlobalVariablesUpdated);
3283 (0, _elementor_editor_v1_adapters.__privateListenTo)((0, _elementor_editor_v1_adapters.commandEndEvent)("document/save/update"), notifyGlobalVariablesUpdated);
3284 });
3285 };
3286
3287 //#endregion
3288 //#region packages/packages/core/editor-variables/src/mcp/manage-variable-tool.ts
3289 var MCP_PROXY_URL = "elementor/v1/mcp-proxy";
3290 var TOOL_NAME = "manage-global-variable";
3291 var VARIABLE_TYPES = {
3292 COLOR: "global-color-variable",
3293 FONT: "global-font-variable",
3294 SIZE: "global-size-variable",
3295 CUSTOM_SIZE: "global-custom-size-variable"
3296 };
3297 var initManageVariableTool = (reg) => {
3298 const { addTool, resource } = reg;
3299 const RUNTIME_ALLOWED_VARIABLE_TYPES = (0, _elementor_utils.isProActive)() ? [
3300 VARIABLE_TYPES.COLOR,
3301 VARIABLE_TYPES.FONT,
3302 VARIABLE_TYPES.SIZE,
3303 VARIABLE_TYPES.CUSTOM_SIZE
3304 ] : [VARIABLE_TYPES.COLOR, VARIABLE_TYPES.FONT];
3305 resource("manage-global-variable-guide", MANAGE_VARIABLES_GUIDE_URI, {
3306 title: "Manage Global Variable Guide",
3307 description: "Detailed guide for using the manage-global-variable tool",
3308 mimeType: "text/plain"
3309 }, async (uri) => {
3310 const { data } = await (0, _elementor_http_client.httpService)().get(MCP_PROXY_URL, { params: { uri: uri.href } });
3311 return { contents: [{
3312 uri: uri.href,
3313 mimeType: "text/plain",
3314 text: data.data
3315 }] };
3316 });
3317 addTool({
3318 name: TOOL_NAME,
3319 description: "Manage V4 global variables (color, font, size, custom-size). Read the guide resource before use. font = single Google Font family name, no fallback stacks, size = measured unit, custom-size = calculated values",
3320 schema: {
3321 action: _elementor_schema.z.enum([
3322 "create",
3323 "update",
3324 "delete"
3325 ]),
3326 id: _elementor_schema.z.string().optional().describe("Variable id — required for update/delete. Get from the global-variables resource."),
3327 type: _elementor_schema.z.enum(RUNTIME_ALLOWED_VARIABLE_TYPES),
3328 label: _elementor_schema.z.string().describe("Variable label (lowercase, dash-separated) — required for create/update."),
3329 value: _elementor_schema.z.string().optional().describe("Plain CSS value — required for create/update. Color: hex/rgba/hsl. Font: single Google Font family name only — no fallback stacks, no generic families. Size: value with unit e.g. \"16px\", or \"auto\" (Pro). Do NOT pass JSON.")
3330 },
3331 outputSchema: {
3332 status: _elementor_schema.z.enum(["ok"]).describe("Operation status"),
3333 message: _elementor_schema.z.string().optional().describe("Error details if status is error")
3334 },
3335 requiredResources: [{
3336 uri: MANAGE_VARIABLES_GUIDE_URI,
3337 description: "Full guide for variable types, naming rules, and usage"
3338 }, {
3339 uri: GLOBAL_VARIABLES_URI,
3340 description: "Current global variables — check before creating to avoid duplicates"
3341 }],
3342 isDestructive: true,
3343 handler: async (params) => {
3344 const { data } = await (0, _elementor_http_client.httpService)().post(MCP_PROXY_URL, {
3345 tool: TOOL_NAME,
3346 input: params
3347 });
3348 const payload = data.data;
3349 if (payload.variable && typeof payload.watermark === "number") applyLocalMutation(params.action, payload.variable, payload.watermark);
3350 return { status: "ok" };
3351 }
3352 });
3353 };
3354
3355 //#endregion
3356 //#region packages/packages/core/editor-variables/src/mcp/index.ts
3357 function initMcp(reg, canvasMcpEntry) {
3358 window.addEventListener("elementor/init", () => {
3359 initManageVariableTool(reg);
3360 initVariablesResource(reg, canvasMcpEntry);
3361 }, { once: true });
3362 }
3363
3364 //#endregion
3365 //#region packages/packages/core/editor-variables/src/components/fields/color-field.tsx
3366 var ColorField = ({ value, onChange, onValidationChange }) => {
3367 const [color, setColor] = (0, react.useState)(value);
3368 const [errorMessage, setErrorMessage] = (0, react.useState)("");
3369 const defaultRef = (0, react.useRef)(null);
3370 const anchorRef = usePopoverContentRef() ?? defaultRef.current;
3371 const handleChange = (newValue) => {
3372 setColor(newValue);
3373 const errorMsg = validateValue(newValue);
3374 setErrorMessage(errorMsg);
3375 onValidationChange?.(errorMsg);
3376 onChange(errorMsg ? "" : newValue);
3377 };
3378 return /* @__PURE__ */ react.createElement(_elementor_ui.UnstableColorField, {
3379 id: "color-variable-field",
3380 size: "tiny",
3381 fullWidth: true,
3382 value: color,
3383 onChange: handleChange,
3384 error: errorMessage || void 0,
3385 slotProps: { colorPicker: {
3386 anchorEl: anchorRef,
3387 anchorOrigin: {
3388 vertical: "top",
3389 horizontal: "right"
3390 },
3391 transformOrigin: {
3392 vertical: "top",
3393 horizontal: -10
3394 },
3395 slotProps: { colorIndicator: {
3396 size: "inherit",
3397 sx: { borderRadius: .5 }
3398 } }
3399 } }
3400 });
3401 };
3402
3403 //#endregion
3404 //#region packages/packages/core/editor-variables/src/components/fields/font-field.tsx
3405 var FontField = ({ value, onChange, onValidationChange }) => {
3406 const [fontFamily, setFontFamily] = (0, react.useState)(value);
3407 const defaultRef = (0, react.useRef)(null);
3408 const anchorRef = usePopoverContentRef() ?? defaultRef.current;
3409 const fontPopoverState = (0, _elementor_ui.usePopupState)({ variant: "popover" });
3410 const fontFamilies = (0, _elementor_editor_controls.useFontFamilies)();
3411 const sectionWidth = (0, _elementor_editor_ui.useSectionWidth)();
3412 const mapFontSubs = (0, react.useMemo)(() => {
3413 return fontFamilies.map(({ label, fonts }) => ({
3414 label,
3415 items: fonts
3416 }));
3417 }, [fontFamilies]);
3418 const handleChange = (newValue) => {
3419 setFontFamily(newValue);
3420 const errorMsg = validateValue(newValue);
3421 onValidationChange?.(errorMsg);
3422 onChange(errorMsg ? "" : newValue);
3423 };
3424 const handleFontFamilyChange = (newFontFamily) => {
3425 handleChange(newFontFamily);
3426 fontPopoverState.close();
3427 };
3428 const id = (0, react.useId)();
3429 return /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement(_elementor_ui.UnstableTag, {
3430 id,
3431 variant: "outlined",
3432 label: fontFamily,
3433 endIcon: /* @__PURE__ */ react.createElement(_elementor_icons.ChevronDownIcon, { fontSize: "tiny" }),
3434 ...(0, _elementor_ui.bindTrigger)(fontPopoverState),
3435 fullWidth: true
3436 }), /* @__PURE__ */ react.createElement(_elementor_ui.Popover, {
3437 disablePortal: true,
3438 disableScrollLock: true,
3439 anchorEl: anchorRef,
3440 anchorOrigin: {
3441 vertical: "top",
3442 horizontal: "right"
3443 },
3444 transformOrigin: {
3445 vertical: "top",
3446 horizontal: -28
3447 },
3448 ...(0, _elementor_ui.bindPopover)(fontPopoverState)
3449 }, /* @__PURE__ */ react.createElement(_elementor_editor_controls.ItemSelector, {
3450 id: "font-family-variables-selector",
3451 itemsList: mapFontSubs,
3452 selectedItem: fontFamily,
3453 onItemChange: handleFontFamilyChange,
3454 onClose: fontPopoverState.close,
3455 sectionWidth,
3456 title: (0, _wordpress_i18n.__)("Font family", "elementor"),
3457 itemStyle: (item) => ({ fontFamily: item.value }),
3458 onDebounce: _elementor_editor_controls.enqueueFont,
3459 icon: _elementor_icons.TextIcon
3460 })));
3461 };
3462
3463 //#endregion
3464 //#region packages/packages/core/editor-variables/src/prop-types/size-variable-prop-type.ts
3465 var sizeVariablePropTypeUtil = (0, _elementor_editor_props.createPropUtils)("global-size-variable", _elementor_schema.z.string());
3466
3467 //#endregion
3468 //#region packages/packages/core/editor-variables/src/transformers/empty-transformer.tsx
3469 var EmptyTransformer = (0, _elementor_editor_canvas.createTransformer)((_value) => {
3470 return null;
3471 });
3472
3473 //#endregion
3474 //#region packages/packages/core/editor-variables/src/register-variable-types.tsx
3475 function registerVariableTypes() {
3476 registerVariableType({
3477 key: colorVariablePropTypeUtil.key,
3478 valueField: ColorField,
3479 icon: _elementor_icons.BrushIcon,
3480 propTypeUtil: colorVariablePropTypeUtil,
3481 fallbackPropTypeUtil: _elementor_editor_props.colorPropTypeUtil,
3482 variableType: "color",
3483 startIcon: ({ value }) => /* @__PURE__ */ react.createElement(ColorIndicator, {
3484 size: "inherit",
3485 component: "span",
3486 value
3487 }),
3488 defaultValue: "#ffffff",
3489 menuActionsFactory: ({ variable, variableId, handlers }) => {
3490 const actions = [];
3491 if (variable.sync_to_v3) actions.push({
3492 name: (0, _wordpress_i18n.__)("Stop syncing to Global Colors", "elementor"),
3493 icon: _elementor_icons.RefreshOffIcon,
3494 color: "text.primary",
3495 onClick: () => handlers.onStopSync(variableId)
3496 });
3497 else actions.push({
3498 name: (0, _wordpress_i18n.__)("Sync to Global Colors", "elementor"),
3499 icon: _elementor_icons.RefreshIcon,
3500 color: "text.primary",
3501 onClick: () => handlers.onStartSync(variableId)
3502 });
3503 return actions;
3504 }
3505 });
3506 registerVariableType({
3507 key: fontVariablePropTypeUtil.key,
3508 valueField: FontField,
3509 icon: _elementor_icons.TextIcon,
3510 propTypeUtil: fontVariablePropTypeUtil,
3511 fallbackPropTypeUtil: _elementor_editor_props.stringPropTypeUtil,
3512 variableType: "font",
3513 defaultValue: "Roboto"
3514 });
3515 const sizePromotions = {
3516 isActive: false,
3517 icon: _elementor_icons.ExpandDiagonalIcon,
3518 propTypeUtil: sizeVariablePropTypeUtil,
3519 fallbackPropTypeUtil: _elementor_editor_props.sizePropTypeUtil,
3520 styleTransformer: EmptyTransformer,
3521 variableType: "size",
3522 selectionFilter: () => [],
3523 emptyState: /* @__PURE__ */ react.createElement(_elementor_editor_ui.CtaButton, {
3524 size: "small",
3525 href: "https://go.elementor.com/go-pro-panel-size-variable/",
3526 onClick: () => (0, _elementor_editor_controls.trackUpgradePromotionClick)({
3527 target_name: "variables_popover",
3528 location_l1: "variables_list"
3529 })
3530 })
3531 };
3532 registerVariableType({
3533 ...sizePromotions,
3534 key: sizeVariablePropTypeUtil.key,
3535 defaultValue: "0px"
3536 });
3537 registerVariableType({
3538 ...sizePromotions,
3539 key: "global-custom-size-variable"
3540 });
3541 }
3542
3543 //#endregion
3544 //#region packages/packages/core/editor-variables/src/renderers/style-variables-renderer.tsx
3545 var VARIABLES_WRAPPER = ":root";
3546 function StyleVariablesRenderer() {
3547 const container = usePortalContainer();
3548 const styleVariables = useStyleVariables();
3549 const hasVariables = Object.keys(styleVariables).length > 0;
3550 if (!container || !hasVariables) return null;
3551 const cssVariables = convertToCssVariables(styleVariables);
3552 const wrappedCss = `${VARIABLES_WRAPPER}{${cssVariables}}`;
3553 return /* @__PURE__ */ react.createElement(_elementor_ui.Portal, { container }, /* @__PURE__ */ react.createElement("style", {
3554 "data-e-style-id": "e-variables",
3555 key: wrappedCss
3556 }, wrappedCss));
3557 }
3558 function usePortalContainer() {
3559 return (0, _elementor_editor_v1_adapters.__privateUseListenTo)((0, _elementor_editor_v1_adapters.commandEndEvent)("editor/documents/attach-preview"), () => (0, _elementor_editor_v1_adapters.getCanvasIframeDocument)()?.head);
3560 }
3561 function useStyleVariables() {
3562 const [variables, setVariables] = (0, react.useState)({});
3563 (0, react.useEffect)(() => {
3564 const unsubscribe = styleVariablesRepository.subscribe(setVariables);
3565 return () => {
3566 unsubscribe();
3567 };
3568 }, []);
3569 return variables;
3570 }
3571 function cssVariableDeclaration(key, variable) {
3572 return `--${variable?.deleted ? key : variable.label}:${variable.value};`;
3573 }
3574 function convertToCssVariables(variables) {
3575 return Object.entries(variables).map(([key, variable]) => cssVariableDeclaration(key, variable)).join("");
3576 }
3577
3578 //#endregion
3579 //#region packages/packages/core/editor-variables/src/prop-types/custom-size-variable-prop-type.ts
3580 var customSizeVariablePropTypeUtil = (0, _elementor_editor_props.createPropUtils)("global-custom-size-variable", _elementor_schema.z.string());
3581
3582 //#endregion
3583 //#region packages/packages/core/editor-variables/src/utils/size-value.ts
3584 var DEFAULT_UNIT = "px";
3585 var CUSTOM_SIZE_LABEL = "fx";
3586 function sizeValue(value) {
3587 if (sizeVariablePropTypeUtil.isValid(value) || customSizeVariablePropTypeUtil.isValid(value)) return getVariable(value?.value)?.value;
3588 if (_elementor_editor_props.sizePropTypeUtil.isValid(value)) {
3589 const { size, unit } = value.value;
3590 if ("custom" !== unit) return `${size ?? 0}${unit ?? DEFAULT_UNIT}`;
3591 if (!size) return CUSTOM_SIZE_LABEL;
3592 return size;
3593 }
3594 return "";
3595 }
3596
3597 //#endregion
3598 //#region packages/packages/core/editor-variables/src/components/variables-repeater-item-slot.tsx
3599 var useColorVariable = (value) => {
3600 const variableId = value?.value?.color?.value;
3601 return getVariable(variableId || "");
3602 };
3603 var BackgroundRepeaterColorIndicator = ({ value }) => {
3604 const colorVariable = useColorVariable(value);
3605 return /* @__PURE__ */ react.createElement(ColorIndicator, {
3606 component: "span",
3607 size: "inherit",
3608 value: colorVariable?.value
3609 });
3610 };
3611 var BackgroundRepeaterLabel = ({ value }) => {
3612 const colorVariable = useColorVariable(value);
3613 return /* @__PURE__ */ react.createElement(_elementor_ui.Box, { component: "span" }, colorVariable?.label);
3614 };
3615 var BoxShadowRepeaterColorIndicator = ({ value }) => {
3616 const colorVariable = useColorVariable(value);
3617 return /* @__PURE__ */ react.createElement(ColorIndicator, {
3618 component: "span",
3619 size: "inherit",
3620 value: colorVariable?.value
3621 });
3622 };
3623 var FilterDropShadowIconIndicator = ({ value }) => {
3624 const { args } = _elementor_editor_props.cssFilterFunctionPropUtil.extract(value) || {};
3625 const { color } = _elementor_editor_props.dropShadowFilterPropTypeUtil.extract(args) || {};
3626 const colorVariable = getVariable(color?.value || "");
3627 return /* @__PURE__ */ react.createElement(ColorIndicator, {
3628 component: "span",
3629 size: "inherit",
3630 value: colorVariable?.value
3631 });
3632 };
3633 var FilterSingleSizeRepeaterLabel = ({ value }) => {
3634 const cssFilterFunction = _elementor_editor_props.cssFilterFunctionPropUtil.extract(value);
3635 if (_elementor_editor_props.dropShadowFilterPropTypeUtil.isValid(cssFilterFunction?.args)) return null;
3636 const args = cssFilterFunction?.args;
3637 const func = cssFilterFunction?.func?.value ?? "";
3638 const rendered = sizeValue(args?.value?.size);
3639 return /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement(_elementor_ui.Box, {
3640 component: "span",
3641 style: { textTransform: "capitalize" }
3642 }, `${func}: `), /* @__PURE__ */ react.createElement(_elementor_ui.Box, { component: "span" }, rendered));
3643 };
3644 var FilterDropShadowRepeaterLabel = ({ value }) => {
3645 const { args } = _elementor_editor_props.cssFilterFunctionPropUtil.extract(value) || {};
3646 const { xAxis, yAxis, blur } = _elementor_editor_props.dropShadowFilterPropTypeUtil.extract(args) || {};
3647 const labels = [];
3648 for (const val of [
3649 xAxis,
3650 yAxis,
3651 blur
3652 ]) {
3653 const rendered = sizeValue(val);
3654 if (rendered) labels.push(rendered);
3655 }
3656 return /* @__PURE__ */ react.createElement(_elementor_ui.Box, { component: "span" }, (0, _wordpress_i18n.__)("Drop shadow:", "elementor"), " ", labels.join(" "));
3657 };
3658 var BoxShadowRepeaterLabel = ({ value }) => {
3659 const { position, hOffset, vOffset, blur, spread } = _elementor_editor_props.shadowPropTypeUtil.extract(value) || {};
3660 const labels = [];
3661 for (const val of [
3662 hOffset,
3663 vOffset,
3664 blur,
3665 spread
3666 ]) {
3667 const rendered = sizeValue(val);
3668 if (rendered) labels.push(rendered);
3669 }
3670 const positionLabel = position?.value || "outset";
3671 return /* @__PURE__ */ react.createElement(_elementor_ui.Box, {
3672 component: "span",
3673 style: { textTransform: "capitalize" }
3674 }, positionLabel, ": ", labels.join(" "));
3675 };
3676 var TransformRepeaterLabel = ({ value }) => {
3677 const labels = [];
3678 if (_elementor_editor_props.moveTransformPropTypeUtil.isValid(value)) {
3679 labels.push((0, _wordpress_i18n.__)("Move:", "elementor"));
3680 const { x, y, z } = _elementor_editor_props.moveTransformPropTypeUtil.extract(value) || {};
3681 for (const val of [
3682 x,
3683 y,
3684 z
3685 ]) {
3686 const rendered = sizeValue(val);
3687 if (rendered) labels.push(rendered);
3688 }
3689 }
3690 return /* @__PURE__ */ react.createElement(_elementor_ui.Box, { component: "span" }, labels.join(" "));
3691 };
3692 var TransitionsSizeVariableLabel = ({ value: prop }) => {
3693 let label = "";
3694 const variable = getVariable(prop?.value?.size?.value || "");
3695 if (variable && _elementor_editor_props.selectionSizePropTypeUtil.isValid(prop)) {
3696 const selection = prop.value?.selection?.value?.key?.value;
3697 if (selection) label += `${selection}: `;
3698 label += variable?.value;
3699 }
3700 return /* @__PURE__ */ react.createElement(_elementor_ui.Box, { component: "span" }, label);
3701 };
3702
3703 //#endregion
3704 //#region packages/packages/core/editor-variables/src/repeater-injections.ts
3705 function registerRepeaterInjections() {
3706 backgroundOverlayRepeaterInjections();
3707 boxShadowRepeaterInjections();
3708 transitionsRepeaterInjections();
3709 transformRepeaterInjections();
3710 filterRepeaterInjections();
3711 }
3712 function backgroundOverlayRepeaterInjections() {
3713 (0, _elementor_editor_controls.injectIntoRepeaterItemIcon)({
3714 id: "background-color-variables-icon",
3715 component: BackgroundRepeaterColorIndicator,
3716 condition: ({ value }) => {
3717 return hasAssignedColorVariable(_elementor_editor_props.backgroundColorOverlayPropTypeUtil.extract(value)?.color);
3718 }
3719 });
3720 (0, _elementor_editor_controls.injectIntoRepeaterItemLabel)({
3721 id: "background-color-variables-label",
3722 component: BackgroundRepeaterLabel,
3723 condition: ({ value }) => {
3724 return hasAssignedColorVariable(_elementor_editor_props.backgroundColorOverlayPropTypeUtil.extract(value)?.color);
3725 }
3726 });
3727 }
3728 function boxShadowRepeaterInjections() {
3729 (0, _elementor_editor_controls.injectIntoRepeaterItemIcon)({
3730 id: "box-shadow-color-variables-icon",
3731 component: BoxShadowRepeaterColorIndicator,
3732 condition: ({ value }) => {
3733 const { color } = _elementor_editor_props.shadowPropTypeUtil.extract(value) || {};
3734 return hasAssignedColorVariable(color);
3735 }
3736 });
3737 (0, _elementor_editor_controls.injectIntoRepeaterItemLabel)({
3738 id: "color-variables-box-shadow-label",
3739 component: BoxShadowRepeaterLabel,
3740 condition: ({ value }) => {
3741 const { hOffset, vOffset, blur, spread } = _elementor_editor_props.shadowPropTypeUtil.extract(value) || {};
3742 return hasAssignedSizeVariable(hOffset) || hasAssignedSizeVariable(vOffset) || hasAssignedSizeVariable(blur) || hasAssignedSizeVariable(spread);
3743 }
3744 });
3745 }
3746 function transformRepeaterInjections() {
3747 (0, _elementor_editor_controls.injectIntoRepeaterItemLabel)({
3748 id: "transform-size-variables-label",
3749 component: TransformRepeaterLabel,
3750 condition: ({ value }) => {
3751 if (_elementor_editor_props.moveTransformPropTypeUtil.isValid(value)) {
3752 const { x: xAxis, y: yAxis, z: zAxis } = _elementor_editor_props.moveTransformPropTypeUtil.extract(value) || {};
3753 return hasAssignedSizeVariable(xAxis) || hasAssignedSizeVariable(yAxis) || hasAssignedSizeVariable(zAxis);
3754 }
3755 return false;
3756 }
3757 });
3758 }
3759 function transitionsRepeaterInjections() {
3760 (0, _elementor_editor_controls.injectIntoRepeaterItemLabel)({
3761 id: "transition-size-variables-label",
3762 component: TransitionsSizeVariableLabel,
3763 condition: ({ value }) => {
3764 return hasAssignedSizeVariable(_elementor_editor_props.selectionSizePropTypeUtil.extract(value)?.size);
3765 }
3766 });
3767 }
3768 function filterRepeaterInjections() {
3769 (0, _elementor_editor_controls.injectIntoRepeaterItemIcon)({
3770 id: "filters-color-variables-icon",
3771 component: FilterDropShadowIconIndicator,
3772 condition: ({ value }) => {
3773 if (!_elementor_editor_props.cssFilterFunctionPropUtil.isValid(value)) return false;
3774 const args = _elementor_editor_props.cssFilterFunctionPropUtil.extract(value)?.args;
3775 if (_elementor_editor_props.dropShadowFilterPropTypeUtil.isValid(args)) return hasAssignedColorVariable(_elementor_editor_props.dropShadowFilterPropTypeUtil.extract(args)?.color);
3776 return false;
3777 }
3778 });
3779 (0, _elementor_editor_controls.injectIntoRepeaterItemLabel)({
3780 id: "filters-drop-shadow-size-variables-label",
3781 component: FilterDropShadowRepeaterLabel,
3782 condition: ({ value }) => {
3783 if (!_elementor_editor_props.cssFilterFunctionPropUtil.isValid(value)) return false;
3784 const args = _elementor_editor_props.cssFilterFunctionPropUtil.extract(value)?.args;
3785 if (_elementor_editor_props.dropShadowFilterPropTypeUtil.isValid(args)) {
3786 const { xAxis, yAxis, blur } = _elementor_editor_props.dropShadowFilterPropTypeUtil.extract(args) || {};
3787 return hasAssignedSizeVariable(xAxis) || hasAssignedSizeVariable(yAxis) || hasAssignedSizeVariable(blur);
3788 }
3789 return false;
3790 }
3791 });
3792 (0, _elementor_editor_controls.injectIntoRepeaterItemLabel)({
3793 id: "filters-size-variables-label",
3794 component: FilterSingleSizeRepeaterLabel,
3795 condition: ({ value }) => {
3796 if (!_elementor_editor_props.cssFilterFunctionPropUtil.isValid(value)) return false;
3797 const args = _elementor_editor_props.cssFilterFunctionPropUtil.extract(value)?.args;
3798 return hasAssignedSizeVariable(args?.value?.size);
3799 }
3800 });
3801 }
3802 function hasAssignedSizeVariable(value) {
3803 if (sizeVariablePropTypeUtil.isValid(value)) return true;
3804 if (customSizeVariablePropTypeUtil.isValid(value)) return true;
3805 return false;
3806 }
3807 function hasAssignedColorVariable(value) {
3808 return !!colorVariablePropTypeUtil.isValid(value);
3809 }
3810
3811 //#endregion
3812 //#region packages/packages/core/editor-variables/src/init.ts
3813 var { registerPopoverAction } = _elementor_menus.controlActionsMenu;
3814 function init() {
3815 registerVariableTypes();
3816 registerRepeaterInjections();
3817 (0, _elementor_editor_controls.registerControlReplacement)({
3818 component: VariableControl,
3819 condition: ({ value, placeholder }) => {
3820 if (hasVariableAssigned(value)) return true;
3821 if (value) return false;
3822 return hasVariableAssigned(placeholder);
3823 }
3824 });
3825 registerPopoverAction({
3826 id: "variables",
3827 priority: 40,
3828 useProps: usePropVariableAction
3829 });
3830 service.init();
3831 initMcp((0, _elementor_editor_mcp.getMCPByDomain)("variables", { instructions: `Everything related to V4 ( Atomic ) variables.
3832 # Global variables
3833 - Create/update/delete global variables
3834 - Get list of global variables
3835 - Get details of a global variable
3836 ` }), (0, _elementor_editor_mcp.getMCPByDomain)("canvas"));
3837 (0, _elementor_editor.injectIntoTop)({
3838 id: "canvas-style-variables-render",
3839 component: StyleVariablesRenderer
3840 });
3841 (0, _elementor_editor.injectIntoLogic)({
3842 id: "variables-import-listener",
3843 component: GlobalStylesImportListener
3844 });
3845 (0, _elementor_editor.injectIntoLogic)({
3846 id: "mcp-variable-connect-listener",
3847 component: McpVariableConnectListener
3848 });
3849 }
3850 function hasVariableAssigned(value) {
3851 if ((0, _elementor_editor_props.isTransformable)(value)) return hasVariableType(value.$$type);
3852 return false;
3853 }
3854
3855 //#endregion
3856 //#region packages/packages/core/editor-variables/src/utils/llm-propvalue-label-resolver.ts
3857 var defaultResolver = (key) => (value) => {
3858 const idOrLabel = String(value);
3859 return {
3860 $$type: key,
3861 value: service.variables()[idOrLabel] ? idOrLabel : service.findIdByLabel(idOrLabel)
3862 };
3863 };
3864 var globalVariablesLLMResolvers = {
3865 "global-color-variable": defaultResolver("global-color-variable"),
3866 "global-font-variable": defaultResolver("global-font-variable"),
3867 "global-size-variable": defaultResolver("global-size-variable")
3868 };
3869
3870 //#endregion
3871 //#region packages/packages/core/editor-variables/src/index.ts
3872 var src_exports = /* @__PURE__ */ __exportAll({
3873 GLOBAL_VARIABLES_URI: () => GLOBAL_VARIABLES_URI,
3874 Utils: () => Utils,
3875 VariablesManagerPanelEmbedded: () => VariablesManagerPanelEmbedded,
3876 getMenuActionsForVariable: () => getMenuActionsForVariable,
3877 hasVariable: () => hasVariable,
3878 init: () => init,
3879 registerVariableType: () => registerVariableType,
3880 registerVariableTypes: () => registerVariableTypes,
3881 service: () => service,
3882 sizeVariablePropTypeUtil: () => sizeVariablePropTypeUtil,
3883 trackVariablesManagerEvent: () => trackVariablesManagerEvent
3884 });
3885 var Utils = { globalVariablesLLMResolvers };
3886
3887 //#endregion
3888 //#region \0elementor-package-library-entry
3889 (window.elementorV2 = window.elementorV2 || {}).editorVariables = src_exports;
3890
3891 //#endregion
3892 })(React, elementorV2.editorCurrentUser, elementorV2.editorPanels, elementorV2.editorUi, elementorV2.icons, elementorV2.ui, wp.i18n, elementorV2.events, elementorV2.editorCanvas, elementorV2.editorProps, elementorV2.schema, elementorV2.httpClient, elementorV2.editorV1Adapters, elementorV2.editorControls, elementorV2.utils, elementorV2.editor, elementorV2.editorMcp, elementorV2.menus);
3893 window.elementorV2.editorVariables?.init?.();
3894 //# sourceMappingURL=editor-variables.js.map