@elementor/editor-variables 0.16.0 → 3.32.0-20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/index.d.mts +19 -1
  3. package/dist/index.d.ts +19 -1
  4. package/dist/index.js +1397 -885
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +1399 -871
  7. package/dist/index.mjs.map +1 -1
  8. package/package.json +16 -14
  9. package/src/api.ts +18 -2
  10. package/src/components/fields/color-field.tsx +3 -3
  11. package/src/components/fields/font-field.tsx +21 -10
  12. package/src/components/fields/label-field.tsx +31 -5
  13. package/src/components/ui/delete-confirmation-dialog.tsx +4 -7
  14. package/src/components/ui/deleted-variable-alert.tsx +47 -0
  15. package/src/components/ui/edit-confirmation-dialog.tsx +75 -0
  16. package/src/components/ui/missing-variable-alert.tsx +39 -0
  17. package/src/components/ui/no-variables.tsx +59 -26
  18. package/src/components/ui/tags/assigned-tag.tsx +21 -19
  19. package/src/components/ui/tags/deleted-tag.tsx +29 -18
  20. package/src/components/ui/tags/missing-tag.tsx +25 -0
  21. package/src/components/ui/variable/assigned-variable.tsx +11 -14
  22. package/src/components/ui/variable/deleted-variable.tsx +115 -7
  23. package/src/components/ui/variable/missing-variable.tsx +44 -0
  24. package/src/components/variable-creation.tsx +135 -0
  25. package/src/components/variable-edit.tsx +221 -0
  26. package/src/components/variable-restore.tsx +117 -0
  27. package/src/components/variable-selection-popover.tsx +91 -92
  28. package/src/components/variables-manager/variables-manager-panel.tsx +115 -0
  29. package/src/components/variables-selection.tsx +148 -0
  30. package/src/context/variable-selection-popover.context.tsx +19 -0
  31. package/src/context/variable-type-context.tsx +23 -0
  32. package/src/controls/variable-control.tsx +26 -0
  33. package/src/create-style-variables-repository.ts +44 -5
  34. package/src/hooks/use-initial-value.ts +22 -0
  35. package/src/hooks/use-permissions.ts +15 -0
  36. package/src/hooks/use-prop-variable-action.tsx +53 -0
  37. package/src/hooks/use-prop-variables.ts +6 -0
  38. package/src/index.ts +1 -0
  39. package/src/init.ts +33 -4
  40. package/src/register-variable-types.tsx +29 -0
  41. package/src/renderers/style-variables-renderer.tsx +10 -4
  42. package/src/repeater-injections.ts +5 -1
  43. package/src/service.ts +8 -4
  44. package/src/sync/enqueue-font.ts +7 -0
  45. package/src/sync/types.ts +5 -0
  46. package/src/transformers/inheritance-transformer.tsx +30 -0
  47. package/src/transformers/utils/resolve-css-variable.ts +24 -0
  48. package/src/transformers/variable-transformer.ts +8 -3
  49. package/src/types.ts +1 -1
  50. package/src/utils/tracking.ts +39 -0
  51. package/src/utils/validations.ts +40 -6
  52. package/src/variables-registry/create-variable-type-registry.ts +77 -0
  53. package/src/variables-registry/variable-type-registry.ts +3 -0
  54. package/src/components/color-variable-creation.tsx +0 -86
  55. package/src/components/color-variable-edit.tsx +0 -138
  56. package/src/components/color-variables-selection.tsx +0 -130
  57. package/src/components/font-variable-creation.tsx +0 -86
  58. package/src/components/font-variable-edit.tsx +0 -138
  59. package/src/components/font-variables-selection.tsx +0 -129
  60. package/src/components/variable-selection-popover.context.ts +0 -7
  61. package/src/controls/color-variable-control.tsx +0 -33
  62. package/src/controls/font-variable-control.tsx +0 -31
  63. package/src/hooks/use-prop-color-variable-action.tsx +0 -25
  64. package/src/hooks/use-prop-font-variable-action.tsx +0 -25
  65. package/src/init-color-variables.ts +0 -27
  66. package/src/init-font-variables.ts +0 -24
  67. package/src/utils.ts +0 -20
package/dist/index.js CHANGED
@@ -30,63 +30,123 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
- init: () => init
33
+ init: () => init,
34
+ registerVariableType: () => registerVariableType
34
35
  });
35
36
  module.exports = __toCommonJS(index_exports);
36
37
 
37
38
  // src/init.ts
38
39
  var import_editor = require("@elementor/editor");
40
+ var import_editor_editing_panel10 = require("@elementor/editor-editing-panel");
41
+ var import_editor_panels2 = require("@elementor/editor-panels");
39
42
 
40
- // src/init-color-variables.ts
41
- var import_editor_canvas2 = require("@elementor/editor-canvas");
42
- var import_editor_editing_panel9 = require("@elementor/editor-editing-panel");
43
+ // src/components/variables-manager/variables-manager-panel.tsx
44
+ var React = __toESM(require("react"));
45
+ var import_react = require("react");
46
+ var import_editor_panels = require("@elementor/editor-panels");
47
+ var import_editor_ui = require("@elementor/editor-ui");
48
+ var import_editor_v1_adapters = require("@elementor/editor-v1-adapters");
49
+ var import_icons = require("@elementor/icons");
50
+ var import_ui = require("@elementor/ui");
51
+ var import_i18n = require("@wordpress/i18n");
52
+ var id = "variables-manager";
53
+ var { panel, usePanelActions } = (0, import_editor_panels.__createPanel)({
54
+ id,
55
+ component: VariablesManagerPanel,
56
+ allowedEditModes: ["edit", id],
57
+ onOpen: () => {
58
+ (0, import_editor_v1_adapters.changeEditMode)(id);
59
+ },
60
+ onClose: () => {
61
+ (0, import_editor_v1_adapters.changeEditMode)("edit");
62
+ }
63
+ });
64
+ function VariablesManagerPanel() {
65
+ const { close: closePanel } = usePanelActions();
66
+ const isDirty = false;
67
+ usePreventUnload(isDirty);
68
+ return /* @__PURE__ */ React.createElement(import_editor_ui.ThemeProvider, null, /* @__PURE__ */ React.createElement(import_ui.ErrorBoundary, { fallback: /* @__PURE__ */ React.createElement(ErrorBoundaryFallback, null) }, /* @__PURE__ */ React.createElement(import_editor_panels.Panel, null, /* @__PURE__ */ React.createElement(import_editor_panels.PanelHeader, null, /* @__PURE__ */ React.createElement(import_ui.Stack, { p: 1, pl: 2, width: "100%", direction: "row", alignItems: "center" }, /* @__PURE__ */ React.createElement(import_ui.Stack, { width: "100%", direction: "row", gap: 1 }, /* @__PURE__ */ React.createElement(import_editor_panels.PanelHeaderTitle, { sx: { display: "flex", alignItems: "center", gap: 0.5 } }, /* @__PURE__ */ React.createElement(import_icons.FilterIcon, { fontSize: "inherit" }), (0, import_i18n.__)("Variables Manager", "elementor"))), /* @__PURE__ */ React.createElement(
69
+ CloseButton,
70
+ {
71
+ sx: { marginLeft: "auto" },
72
+ onClose: () => {
73
+ closePanel();
74
+ }
75
+ }
76
+ ))), /* @__PURE__ */ React.createElement(
77
+ import_editor_panels.PanelBody,
78
+ {
79
+ sx: {
80
+ display: "flex",
81
+ flexDirection: "column",
82
+ height: "100%"
83
+ }
84
+ },
85
+ /* @__PURE__ */ React.createElement(import_ui.Divider, null),
86
+ /* @__PURE__ */ React.createElement(
87
+ import_ui.Box,
88
+ {
89
+ px: 2,
90
+ sx: {
91
+ flexGrow: 1,
92
+ overflowY: "auto"
93
+ }
94
+ },
95
+ "List"
96
+ )
97
+ ), /* @__PURE__ */ React.createElement(import_editor_panels.PanelFooter, null, /* @__PURE__ */ React.createElement(import_ui.Button, { fullWidth: true, size: "small", color: "global", variant: "contained", disabled: !isDirty }, (0, import_i18n.__)("Save changes", "elementor"))))));
98
+ }
99
+ var CloseButton = ({ onClose, ...props }) => /* @__PURE__ */ React.createElement(import_ui.IconButton, { size: "small", color: "secondary", onClick: onClose, "aria-label": "Close", ...props }, /* @__PURE__ */ React.createElement(import_icons.XIcon, { fontSize: "small" }));
100
+ var ErrorBoundaryFallback = () => /* @__PURE__ */ React.createElement(import_ui.Box, { role: "alert", sx: { minHeight: "100%", p: 2 } }, /* @__PURE__ */ React.createElement(import_ui.Alert, { severity: "error", sx: { mb: 2, maxWidth: 400, textAlign: "center" } }, /* @__PURE__ */ React.createElement("strong", null, (0, import_i18n.__)("Something went wrong", "elementor"))));
101
+ var usePreventUnload = (isDirty) => {
102
+ (0, import_react.useEffect)(() => {
103
+ const handleBeforeUnload = (event) => {
104
+ if (isDirty) {
105
+ event.preventDefault();
106
+ }
107
+ };
108
+ window.addEventListener("beforeunload", handleBeforeUnload);
109
+ return () => {
110
+ window.removeEventListener("beforeunload", handleBeforeUnload);
111
+ };
112
+ }, [isDirty]);
113
+ };
43
114
 
44
- // src/controls/color-variable-control.tsx
45
- var React19 = __toESM(require("react"));
115
+ // src/controls/variable-control.tsx
116
+ var React24 = __toESM(require("react"));
46
117
  var import_editor_controls9 = require("@elementor/editor-controls");
47
- var import_editor_props3 = require("@elementor/editor-props");
118
+
119
+ // src/components/ui/variable/assigned-variable.tsx
120
+ var import_react11 = require("react");
121
+ var React16 = __toESM(require("react"));
122
+ var import_editor_controls5 = require("@elementor/editor-controls");
123
+ var import_icons9 = require("@elementor/icons");
124
+ var import_ui16 = require("@elementor/ui");
125
+
126
+ // src/variables-registry/create-variable-type-registry.ts
127
+ var import_editor_canvas3 = require("@elementor/editor-canvas");
128
+ var import_editor_editing_panel = require("@elementor/editor-editing-panel");
129
+
130
+ // src/transformers/inheritance-transformer.tsx
131
+ var React2 = __toESM(require("react"));
132
+ var import_editor_canvas = require("@elementor/editor-canvas");
133
+ var import_ui3 = require("@elementor/ui");
134
+ var import_i18n3 = require("@wordpress/i18n");
48
135
 
49
136
  // src/components/ui/color-indicator.tsx
50
- var import_ui = require("@elementor/ui");
51
- var ColorIndicator = (0, import_ui.styled)(import_ui.UnstableColorIndicator)(({ theme }) => ({
137
+ var import_ui2 = require("@elementor/ui");
138
+ var ColorIndicator = (0, import_ui2.styled)(import_ui2.UnstableColorIndicator)(({ theme }) => ({
52
139
  borderRadius: `${theme.shape.borderRadius / 2}px`,
53
140
  marginRight: theme.spacing(0.25)
54
141
  }));
55
142
 
56
- // src/components/ui/variable/assigned-variable.tsx
57
- var import_react13 = require("react");
58
- var React16 = __toESM(require("react"));
59
- var import_editor_controls8 = require("@elementor/editor-controls");
60
- var import_icons11 = require("@elementor/icons");
61
- var import_ui18 = require("@elementor/ui");
62
-
63
- // src/components/variable-selection-popover.tsx
64
- var React14 = __toESM(require("react"));
65
- var import_react12 = require("react");
66
- var import_ui16 = require("@elementor/ui");
67
-
68
143
  // src/prop-types/color-variable-prop-type.ts
69
144
  var import_editor_props = require("@elementor/editor-props");
70
145
  var import_schema = require("@elementor/schema");
71
146
  var colorVariablePropTypeUtil = (0, import_editor_props.createPropUtils)("global-color-variable", import_schema.z.string());
72
147
 
73
- // src/prop-types/font-variable-prop-type.ts
74
- var import_editor_props2 = require("@elementor/editor-props");
75
- var import_schema2 = require("@elementor/schema");
76
- var fontVariablePropTypeUtil = (0, import_editor_props2.createPropUtils)("global-font-variable", import_schema2.z.string());
77
-
78
- // src/components/color-variable-creation.tsx
79
- var React3 = __toESM(require("react"));
80
- var import_react5 = require("react");
81
- var import_editor_controls = require("@elementor/editor-controls");
82
- var import_editor_editing_panel = require("@elementor/editor-editing-panel");
83
- var import_editor_ui = require("@elementor/editor-ui");
84
- var import_icons = require("@elementor/icons");
85
- var import_ui4 = require("@elementor/ui");
86
- var import_i18n4 = require("@wordpress/i18n");
87
-
88
- // src/hooks/use-prop-variables.ts
89
- var import_react = require("react");
148
+ // src/service.ts
149
+ var import_i18n2 = require("@wordpress/i18n");
90
150
 
91
151
  // src/api.ts
92
152
  var import_http_client = require("@elementor/http-client");
@@ -102,18 +162,25 @@ var apiClient = {
102
162
  value
103
163
  });
104
164
  },
105
- update: (id, label, value) => {
165
+ update: (id2, label, value) => {
106
166
  return (0, import_http_client.httpService)().put(BASE_PATH + "/update", {
107
- id,
167
+ id: id2,
108
168
  label,
109
169
  value
110
170
  });
111
171
  },
112
- delete: (id) => {
113
- return (0, import_http_client.httpService)().post(BASE_PATH + "/delete", { id });
172
+ delete: (id2) => {
173
+ return (0, import_http_client.httpService)().post(BASE_PATH + "/delete", { id: id2 });
114
174
  },
115
- restore: (id) => {
116
- return (0, import_http_client.httpService)().post(BASE_PATH + "/restore", { id });
175
+ restore: (id2, label, value) => {
176
+ const payload = { id: id2 };
177
+ if (label) {
178
+ payload.label = label;
179
+ }
180
+ if (value) {
181
+ payload.value = value;
182
+ }
183
+ return (0, import_http_client.httpService)().post(BASE_PATH + "/restore", payload);
117
184
  }
118
185
  };
119
186
 
@@ -144,14 +211,14 @@ var Storage = class {
144
211
  localStorage.setItem(STORAGE_WATERMARK_KEY, this.state.watermark.toString());
145
212
  localStorage.setItem(STORAGE_KEY, JSON.stringify(this.state.variables));
146
213
  }
147
- add(id, variable) {
214
+ add(id2, variable) {
148
215
  this.load();
149
- this.state.variables[id] = variable;
216
+ this.state.variables[id2] = variable;
150
217
  localStorage.setItem(STORAGE_KEY, JSON.stringify(this.state.variables));
151
218
  }
152
- update(id, variable) {
219
+ update(id2, variable) {
153
220
  this.load();
154
- this.state.variables[id] = variable;
221
+ this.state.variables[id2] = variable;
155
222
  localStorage.setItem(STORAGE_KEY, JSON.stringify(this.state.variables));
156
223
  }
157
224
  watermark(watermark) {
@@ -170,6 +237,17 @@ var Storage = class {
170
237
  }
171
238
  };
172
239
 
240
+ // src/prop-types/font-variable-prop-type.ts
241
+ var import_editor_props2 = require("@elementor/editor-props");
242
+ var import_schema2 = require("@elementor/schema");
243
+ var fontVariablePropTypeUtil = (0, import_editor_props2.createPropUtils)("global-font-variable", import_schema2.z.string());
244
+
245
+ // src/sync/enqueue-font.ts
246
+ var enqueueFont = (fontFamily, context = "preview") => {
247
+ const extendedWindow = window;
248
+ return extendedWindow.elementor?.helpers?.enqueueFont?.(fontFamily, context) ?? null;
249
+ };
250
+
173
251
  // src/create-style-variables-repository.ts
174
252
  var createStyleVariablesRepository = () => {
175
253
  const variables = {};
@@ -186,19 +264,46 @@ var createStyleVariablesRepository = () => {
186
264
  subscription({ ...variables });
187
265
  }
188
266
  };
189
- const shouldUpdate = (key, newValue) => {
190
- return !(key in variables) || variables[key] !== newValue;
267
+ const shouldUpdate = (key, maybeUpdated) => {
268
+ if (!(key in variables)) {
269
+ return true;
270
+ }
271
+ if (variables[key].label !== maybeUpdated.label) {
272
+ return true;
273
+ }
274
+ if (variables[key].value !== maybeUpdated.value) {
275
+ return true;
276
+ }
277
+ if (!variables[key]?.deleted && maybeUpdated?.deleted) {
278
+ return true;
279
+ }
280
+ if (variables[key]?.deleted && !maybeUpdated?.deleted) {
281
+ return true;
282
+ }
283
+ return false;
191
284
  };
192
285
  const applyUpdates = (updatedVars) => {
193
286
  let hasChanges = false;
194
- for (const [key, { value }] of Object.entries(updatedVars)) {
195
- if (shouldUpdate(key, value)) {
196
- variables[key] = value;
287
+ for (const [key, variable] of Object.entries(updatedVars)) {
288
+ if (shouldUpdate(key, variable)) {
289
+ variables[key] = variable;
290
+ if (variable.type === fontVariablePropTypeUtil.key) {
291
+ fontEnqueue(variable.value);
292
+ }
197
293
  hasChanges = true;
198
294
  }
199
295
  }
200
296
  return hasChanges;
201
297
  };
298
+ const fontEnqueue = (value) => {
299
+ if (!value) {
300
+ return;
301
+ }
302
+ try {
303
+ enqueueFont(value);
304
+ } catch {
305
+ }
306
+ };
202
307
  const update = (updatedVars) => {
203
308
  if (applyUpdates(updatedVars)) {
204
309
  notify();
@@ -240,7 +345,8 @@ var service = {
240
345
  return apiClient.create(type, label, value).then((response) => {
241
346
  const { success, data: payload } = response.data;
242
347
  if (!success) {
243
- throw new Error("Unexpected response from server");
348
+ const errorMessage = payload?.message || (0, import_i18n2.__)("Unexpected response from server", "elementor");
349
+ throw new Error(errorMessage);
244
350
  }
245
351
  return payload;
246
352
  }).then((data) => {
@@ -257,11 +363,12 @@ var service = {
257
363
  };
258
364
  });
259
365
  },
260
- update: (id, { label, value }) => {
261
- return apiClient.update(id, label, value).then((response) => {
366
+ update: (id2, { label, value }) => {
367
+ return apiClient.update(id2, label, value).then((response) => {
262
368
  const { success, data: payload } = response.data;
263
369
  if (!success) {
264
- throw new Error("Unexpected response from server");
370
+ const errorMessage = payload?.message || (0, import_i18n2.__)("Unexpected response from server", "elementor");
371
+ throw new Error(errorMessage);
265
372
  }
266
373
  return payload;
267
374
  }).then((data) => {
@@ -278,8 +385,8 @@ var service = {
278
385
  };
279
386
  });
280
387
  },
281
- delete: (id) => {
282
- return apiClient.delete(id).then((response) => {
388
+ delete: (id2) => {
389
+ return apiClient.delete(id2).then((response) => {
283
390
  const { success, data: payload } = response.data;
284
391
  if (!success) {
285
392
  throw new Error("Unexpected response from server");
@@ -299,8 +406,8 @@ var service = {
299
406
  };
300
407
  });
301
408
  },
302
- restore: (id) => {
303
- return apiClient.restore(id).then((response) => {
409
+ restore: (id2, label, value) => {
410
+ return apiClient.restore(id2, label, value).then((response) => {
304
411
  const { success, data: payload } = response.data;
305
412
  if (!success) {
306
413
  throw new Error("Unexpected response from server");
@@ -328,7 +435,157 @@ var handleWatermark = (operation, newWatermark) => {
328
435
  storage.watermark(newWatermark);
329
436
  };
330
437
 
438
+ // src/transformers/utils/resolve-css-variable.ts
439
+ var resolveCssVariable = (id2, variable) => {
440
+ let name = id2;
441
+ let fallbackValue = "";
442
+ if (variable) {
443
+ fallbackValue = variable.value;
444
+ }
445
+ if (variable && !variable.deleted) {
446
+ name = variable.label;
447
+ }
448
+ if (!name.trim()) {
449
+ return null;
450
+ }
451
+ if (!fallbackValue.trim()) {
452
+ return `var(--${name})`;
453
+ }
454
+ return `var(--${name}, ${fallbackValue})`;
455
+ };
456
+
457
+ // src/transformers/inheritance-transformer.tsx
458
+ var inheritanceTransformer = (0, import_editor_canvas.createTransformer)((id2) => {
459
+ const variables = service.variables();
460
+ const variable = variables[id2];
461
+ if (!variable) {
462
+ return /* @__PURE__ */ React2.createElement("span", null, (0, import_i18n3.__)("Missing variable", "elementor"));
463
+ }
464
+ const showColorIndicator = variable.type === colorVariablePropTypeUtil.key;
465
+ const css = resolveCssVariable(id2, variable);
466
+ return /* @__PURE__ */ React2.createElement(import_ui3.Stack, { direction: "row", spacing: 0.5, sx: { paddingInline: "1px" }, alignItems: "center" }, showColorIndicator && /* @__PURE__ */ React2.createElement(ColorIndicator, { size: "inherit", value: variable.value }), /* @__PURE__ */ React2.createElement(import_ui3.Typography, { variant: "caption", overflow: "hidden", whiteSpace: "nowrap", textOverflow: "ellipsis" }, css));
467
+ });
468
+
469
+ // src/transformers/variable-transformer.ts
470
+ var import_editor_canvas2 = require("@elementor/editor-canvas");
471
+ var variableTransformer = (0, import_editor_canvas2.createTransformer)((id2) => {
472
+ const variables = service.variables();
473
+ if (!variables[id2]) {
474
+ return null;
475
+ }
476
+ return resolveCssVariable(id2, variables[id2]);
477
+ });
478
+
479
+ // src/variables-registry/create-variable-type-registry.ts
480
+ function createVariableTypeRegistry() {
481
+ const variableTypes = {};
482
+ const registerVariableType2 = ({
483
+ icon,
484
+ startIcon,
485
+ valueField,
486
+ propTypeUtil,
487
+ variableType,
488
+ fallbackPropTypeUtil
489
+ }) => {
490
+ if (variableTypes[propTypeUtil.key]) {
491
+ throw new Error(`Variable with key "${propTypeUtil.key}" is already registered.`);
492
+ }
493
+ variableTypes[propTypeUtil.key] = {
494
+ icon,
495
+ startIcon,
496
+ valueField,
497
+ propTypeUtil,
498
+ variableType,
499
+ fallbackPropTypeUtil
500
+ };
501
+ registerTransformer(propTypeUtil.key);
502
+ registerInheritanceTransformer(propTypeUtil.key);
503
+ };
504
+ const registerTransformer = (key) => {
505
+ import_editor_canvas3.styleTransformersRegistry.register(key, variableTransformer);
506
+ };
507
+ const registerInheritanceTransformer = (key) => {
508
+ import_editor_editing_panel.stylesInheritanceTransformersRegistry.register(key, inheritanceTransformer);
509
+ };
510
+ const getVariableType2 = (key) => {
511
+ return variableTypes[key];
512
+ };
513
+ const hasVariableType2 = (key) => {
514
+ return key in variableTypes;
515
+ };
516
+ return {
517
+ registerVariableType: registerVariableType2,
518
+ getVariableType: getVariableType2,
519
+ hasVariableType: hasVariableType2
520
+ };
521
+ }
522
+
523
+ // src/variables-registry/variable-type-registry.ts
524
+ var { registerVariableType, getVariableType, hasVariableType } = createVariableTypeRegistry();
525
+
526
+ // src/components/variable-selection-popover.tsx
527
+ var React14 = __toESM(require("react"));
528
+ var import_react10 = require("react");
529
+ var import_editor_v1_adapters2 = require("@elementor/editor-v1-adapters");
530
+
531
+ // src/context/variable-selection-popover.context.tsx
532
+ var React3 = __toESM(require("react"));
533
+ var import_react2 = require("react");
534
+ var import_ui4 = require("@elementor/ui");
535
+ var PopoverContentRefContext = (0, import_react2.createContext)(null);
536
+ var PopoverContentRefContextProvider = ({ children }) => {
537
+ const [anchorRef, setAnchorRef] = (0, import_react2.useState)(null);
538
+ return /* @__PURE__ */ React3.createElement(PopoverContentRefContext.Provider, { value: anchorRef }, /* @__PURE__ */ React3.createElement(import_ui4.Box, { ref: setAnchorRef }, children));
539
+ };
540
+ var usePopoverContentRef = () => {
541
+ return (0, import_react2.useContext)(PopoverContentRefContext);
542
+ };
543
+
544
+ // src/context/variable-type-context.tsx
545
+ var React4 = __toESM(require("react"));
546
+ var import_react3 = require("react");
547
+ var VariableTypeContext = (0, import_react3.createContext)(null);
548
+ function VariableTypeProvider({ children, propTypeKey }) {
549
+ return /* @__PURE__ */ React4.createElement(VariableTypeContext.Provider, { value: propTypeKey }, children);
550
+ }
551
+ function useVariableType() {
552
+ const context = (0, import_react3.useContext)(VariableTypeContext);
553
+ if (context === null) {
554
+ throw new Error("useVariableType must be used within a VariableTypeProvider");
555
+ }
556
+ return getVariableType(context);
557
+ }
558
+
559
+ // src/hooks/use-permissions.ts
560
+ var import_editor_current_user = require("@elementor/editor-current-user");
561
+ var usePermissions = () => {
562
+ const { canUser } = (0, import_editor_current_user.useCurrentUserCapabilities)();
563
+ return {
564
+ canAssign: () => canUser("edit_posts"),
565
+ canUnlink: () => canUser("edit_posts"),
566
+ canAdd: () => canUser("manage_options"),
567
+ canDelete: () => canUser("manage_options"),
568
+ canEdit: () => canUser("manage_options"),
569
+ canRestore: () => canUser("manage_options"),
570
+ canManageSettings: () => canUser("manage_options")
571
+ };
572
+ };
573
+
574
+ // src/components/variable-creation.tsx
575
+ var React6 = __toESM(require("react"));
576
+ var import_react6 = require("react");
577
+ var import_editor_controls2 = require("@elementor/editor-controls");
578
+ var import_editor_editing_panel2 = require("@elementor/editor-editing-panel");
579
+ var import_editor_ui2 = require("@elementor/editor-ui");
580
+ var import_icons2 = require("@elementor/icons");
581
+ var import_ui6 = require("@elementor/ui");
582
+ var import_i18n6 = require("@wordpress/i18n");
583
+
584
+ // src/hooks/use-initial-value.ts
585
+ var import_editor_controls = require("@elementor/editor-controls");
586
+
331
587
  // src/hooks/use-prop-variables.ts
588
+ var import_react4 = require("react");
332
589
  var useVariable = (key) => {
333
590
  const variables = service.variables();
334
591
  if (!variables?.[key]) {
@@ -351,7 +608,7 @@ var useFilteredVariables = (searchValue, propTypeKey) => {
351
608
  };
352
609
  };
353
610
  var usePropVariables = (propKey) => {
354
- return (0, import_react.useMemo)(() => normalizeVariables(propKey), [propKey]);
611
+ return (0, import_react4.useMemo)(() => normalizeVariables(propKey), [propKey]);
355
612
  };
356
613
  var isNotDeleted = ({ deleted }) => !deleted;
357
614
  var normalizeVariables = (propKey) => {
@@ -363,184 +620,251 @@ var normalizeVariables = (propKey) => {
363
620
  }));
364
621
  };
365
622
  var createVariable = (newVariable) => {
366
- return service.create(newVariable).then(({ id }) => {
367
- return id;
623
+ return service.create(newVariable).then(({ id: id2 }) => {
624
+ return id2;
368
625
  });
369
626
  };
370
627
  var updateVariable = (updateId, { value, label }) => {
371
- return service.update(updateId, { value, label }).then(({ id }) => {
372
- return id;
628
+ return service.update(updateId, { value, label }).then(({ id: id2 }) => {
629
+ return id2;
373
630
  });
374
631
  };
375
632
  var deleteVariable = (deleteId) => {
376
- return service.delete(deleteId).then(({ id }) => {
377
- return id;
633
+ return service.delete(deleteId).then(({ id: id2 }) => {
634
+ return id2;
635
+ });
636
+ };
637
+ var restoreVariable = (restoreId, label, value) => {
638
+ return service.restore(restoreId, label, value).then(({ id: id2 }) => {
639
+ return id2;
378
640
  });
379
641
  };
380
642
 
381
- // src/components/fields/color-field.tsx
382
- var React = __toESM(require("react"));
383
- var import_react3 = require("react");
384
- var import_ui2 = require("@elementor/ui");
385
- var import_i18n2 = require("@wordpress/i18n");
643
+ // src/hooks/use-initial-value.ts
644
+ var useInitialValue = () => {
645
+ const { value: initial } = (0, import_editor_controls.useBoundProp)();
646
+ const hasAssignedVariable2 = hasVariableType(initial?.$$type) && Boolean(initial?.value);
647
+ const variable = useVariable(hasAssignedVariable2 ? initial.value : "");
648
+ if (hasAssignedVariable2) {
649
+ return variable ? variable.value : "";
650
+ }
651
+ return initial?.value ?? "";
652
+ };
653
+
654
+ // src/utils/tracking.ts
655
+ var trackVariableEvent = ({ varType, controlPath, action }) => {
656
+ const extendedWindow = window;
657
+ const config = extendedWindow?.elementorCommon?.eventsManager?.config;
658
+ if (!config?.names?.variables?.[action]) {
659
+ return;
660
+ }
661
+ const name = config.names.variables[action];
662
+ extendedWindow.elementorCommon?.eventsManager?.dispatchEvent(name, {
663
+ location: config.locations.variables,
664
+ secondaryLocation: config.secondaryLocations.variablesPopover,
665
+ trigger: config.triggers.click,
666
+ var_type: varType,
667
+ control_path: controlPath,
668
+ action_type: name
669
+ });
670
+ };
386
671
 
387
672
  // src/utils/validations.ts
388
- var import_i18n = require("@wordpress/i18n");
673
+ var import_i18n4 = require("@wordpress/i18n");
674
+ var ERROR_MESSAGES = {
675
+ MISSING_VARIABLE_NAME: (0, import_i18n4.__)("Give your variable a name.", "elementor"),
676
+ MISSING_VARIABLE_VALUE: (0, import_i18n4.__)("Add a value to complete your variable.", "elementor"),
677
+ INVALID_CHARACTERS: (0, import_i18n4.__)("Use letters, numbers, dashes (-), or underscores (_) for the name.", "elementor"),
678
+ NO_NON_SPECIAL_CHARACTER: (0, import_i18n4.__)("Names have to include at least one non-special character.", "elementor"),
679
+ VARIABLE_LABEL_MAX_LENGTH: (0, import_i18n4.__)("Keep names up to 50 characters.", "elementor"),
680
+ DUPLICATED_LABEL: (0, import_i18n4.__)("This variable name already exists. Please choose a unique name.", "elementor"),
681
+ UNEXPECTED_ERROR: (0, import_i18n4.__)("There was a glitch. Try saving your variable again.", "elementor")
682
+ };
389
683
  var VARIABLE_LABEL_MAX_LENGTH = 50;
684
+ var mapServerError = (error) => {
685
+ if (error?.response?.data?.code === "duplicated_label") {
686
+ return {
687
+ field: "label",
688
+ message: ERROR_MESSAGES.DUPLICATED_LABEL
689
+ };
690
+ }
691
+ return void 0;
692
+ };
390
693
  var validateLabel = (name) => {
391
694
  if (!name.trim()) {
392
- return (0, import_i18n.__)("Missing variable name.", "elementor");
695
+ return ERROR_MESSAGES.MISSING_VARIABLE_NAME;
393
696
  }
394
697
  const allowedChars = /^[a-zA-Z0-9_-]+$/;
395
698
  if (!allowedChars.test(name)) {
396
- return (0, import_i18n.__)("Names can only use letters, numbers, dashes (-) and underscores (_).", "elementor");
699
+ return ERROR_MESSAGES.INVALID_CHARACTERS;
397
700
  }
398
701
  const hasAlphanumeric = /[a-zA-Z0-9]/;
399
702
  if (!hasAlphanumeric.test(name)) {
400
- return (0, import_i18n.__)("Names have to include at least one non-special character.", "elementor");
703
+ return ERROR_MESSAGES.NO_NON_SPECIAL_CHARACTER;
401
704
  }
402
705
  if (VARIABLE_LABEL_MAX_LENGTH < name.length) {
403
- return (0, import_i18n.__)("Variable names can contain up to 50 characters.", "elementor");
706
+ return ERROR_MESSAGES.VARIABLE_LABEL_MAX_LENGTH;
404
707
  }
405
708
  return "";
406
709
  };
407
710
  var labelHint = (name) => {
408
711
  const hintThreshold = VARIABLE_LABEL_MAX_LENGTH * 0.8 - 1;
409
712
  if (hintThreshold < name.length) {
410
- return (0, import_i18n.__)("Variable names can contain up to 50 characters.", "elementor");
713
+ return ERROR_MESSAGES.VARIABLE_LABEL_MAX_LENGTH;
411
714
  }
412
715
  return "";
413
716
  };
414
717
  var validateValue = (value) => {
415
718
  if (!value.trim()) {
416
- return (0, import_i18n.__)("Missing variable value.", "elementor");
719
+ return ERROR_MESSAGES.MISSING_VARIABLE_VALUE;
417
720
  }
418
721
  return "";
419
722
  };
420
723
 
421
- // src/components/variable-selection-popover.context.ts
422
- var import_react2 = require("react");
423
- var PopoverContentRefContext = (0, import_react2.createContext)(null);
424
- var usePopoverContentRef = () => {
425
- return (0, import_react2.useContext)(PopoverContentRefContext);
426
- };
427
-
428
- // src/components/fields/color-field.tsx
429
- var ColorField = ({ value, onChange }) => {
430
- const [color, setColor] = (0, import_react3.useState)(value);
431
- const [errorMessage, setErrorMessage] = (0, import_react3.useState)("");
432
- const defaultRef = (0, import_react3.useRef)(null);
433
- const anchorRef = usePopoverContentRef() ?? defaultRef;
434
- const handleChange = (newValue) => {
435
- setColor(newValue);
436
- const errorMsg = validateValue(newValue);
437
- setErrorMessage(errorMsg);
438
- onChange(errorMsg ? "" : newValue);
724
+ // src/components/fields/label-field.tsx
725
+ var React5 = __toESM(require("react"));
726
+ var import_react5 = require("react");
727
+ var import_ui5 = require("@elementor/ui");
728
+ var import_i18n5 = require("@wordpress/i18n");
729
+ function isLabelEqual(a, b) {
730
+ return a.trim().toLowerCase() === b.trim().toLowerCase();
731
+ }
732
+ var useLabelError = (initialError) => {
733
+ const [error, setError] = (0, import_react5.useState)(initialError ?? { value: "", message: "" });
734
+ return {
735
+ labelFieldError: error,
736
+ setLabelFieldError: setError
439
737
  };
440
- return /* @__PURE__ */ React.createElement(import_ui2.Grid, { container: true, gap: 0.75, alignItems: "center" }, /* @__PURE__ */ React.createElement(import_ui2.Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(import_ui2.FormLabel, { size: "tiny" }, (0, import_i18n2.__)("Value", "elementor"))), /* @__PURE__ */ React.createElement(import_ui2.Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(
441
- import_ui2.UnstableColorField,
442
- {
443
- size: "tiny",
444
- fullWidth: true,
445
- value: color,
446
- onChange: handleChange,
447
- error: errorMessage ?? void 0,
448
- slotProps: {
449
- colorPicker: {
450
- anchorEl: anchorRef.current,
451
- anchorOrigin: { vertical: "top", horizontal: "right" },
452
- transformOrigin: { vertical: "top", horizontal: -10 }
453
- }
454
- }
455
- }
456
- ), errorMessage && /* @__PURE__ */ React.createElement(import_ui2.FormHelperText, { error: true }, errorMessage)));
457
738
  };
458
-
459
- // src/components/fields/label-field.tsx
460
- var React2 = __toESM(require("react"));
461
- var import_react4 = require("react");
462
- var import_ui3 = require("@elementor/ui");
463
- var import_i18n3 = require("@wordpress/i18n");
464
- var LabelField = ({ value, onChange }) => {
465
- const [label, setLabel] = (0, import_react4.useState)(value);
466
- const [errorMessage, setErrorMessage] = (0, import_react4.useState)("");
467
- const [noticeMessage, setNoticeMessage] = (0, import_react4.useState)(() => labelHint(value));
739
+ var LabelField = ({ value, error, onChange }) => {
740
+ const [label, setLabel] = (0, import_react5.useState)(value);
741
+ const [errorMessage, setErrorMessage] = (0, import_react5.useState)("");
742
+ const [noticeMessage, setNoticeMessage] = (0, import_react5.useState)(() => labelHint(value));
468
743
  const handleChange = (newValue) => {
469
744
  setLabel(newValue);
470
- const errorMsg = validateLabel(newValue);
745
+ const errorMsg2 = validateLabel(newValue);
471
746
  const hintMsg = labelHint(newValue);
472
- setErrorMessage(errorMsg);
473
- setNoticeMessage(errorMsg ? "" : hintMsg);
474
- onChange(errorMsg ? "" : newValue);
747
+ setErrorMessage(errorMsg2);
748
+ setNoticeMessage(errorMsg2 ? "" : hintMsg);
749
+ onChange(isLabelEqual(newValue, error?.value ?? "") || errorMsg2 ? "" : newValue);
475
750
  };
476
- const id = (0, import_react4.useId)();
477
- return /* @__PURE__ */ React2.createElement(import_ui3.Grid, { container: true, gap: 0.75, alignItems: "center" }, /* @__PURE__ */ React2.createElement(import_ui3.Grid, { item: true, xs: 12 }, /* @__PURE__ */ React2.createElement(import_ui3.FormLabel, { htmlFor: id, size: "tiny" }, (0, import_i18n3.__)("Name", "elementor"))), /* @__PURE__ */ React2.createElement(import_ui3.Grid, { item: true, xs: 12 }, /* @__PURE__ */ React2.createElement(
478
- import_ui3.TextField,
751
+ const id2 = (0, import_react5.useId)();
752
+ let errorMsg = errorMessage;
753
+ if (isLabelEqual(label, error?.value ?? "") && error?.message) {
754
+ errorMsg = error.message;
755
+ }
756
+ const noticeMsg = errorMsg ? "" : noticeMessage;
757
+ return /* @__PURE__ */ React5.createElement(import_ui5.Grid, { container: true, gap: 0.75, alignItems: "center" }, /* @__PURE__ */ React5.createElement(import_ui5.Grid, { item: true, xs: 12 }, /* @__PURE__ */ React5.createElement(import_ui5.FormLabel, { htmlFor: id2, size: "tiny" }, (0, import_i18n5.__)("Name", "elementor"))), /* @__PURE__ */ React5.createElement(import_ui5.Grid, { item: true, xs: 12 }, /* @__PURE__ */ React5.createElement(
758
+ import_ui5.TextField,
479
759
  {
480
- id,
760
+ id: id2,
481
761
  size: "tiny",
482
762
  fullWidth: true,
483
763
  value: label,
484
- error: !!errorMessage,
764
+ error: !!errorMsg,
485
765
  onChange: (e) => handleChange(e.target.value),
486
766
  inputProps: { maxLength: VARIABLE_LABEL_MAX_LENGTH }
487
767
  }
488
- ), errorMessage && /* @__PURE__ */ React2.createElement(import_ui3.FormHelperText, { error: true }, errorMessage), noticeMessage && /* @__PURE__ */ React2.createElement(import_ui3.FormHelperText, null, noticeMessage)));
768
+ ), errorMsg && /* @__PURE__ */ React5.createElement(import_ui5.FormHelperText, { error: true }, errorMsg), noticeMsg && /* @__PURE__ */ React5.createElement(import_ui5.FormHelperText, null, noticeMsg)));
489
769
  };
490
770
 
491
- // src/components/color-variable-creation.tsx
771
+ // src/components/variable-creation.tsx
492
772
  var SIZE = "tiny";
493
- var ColorVariableCreation = ({ onGoBack, onClose }) => {
494
- const { setValue: setVariable } = (0, import_editor_controls.useBoundProp)(colorVariablePropTypeUtil);
495
- const [color, setColor] = (0, import_react5.useState)("");
496
- const [label, setLabel] = (0, import_react5.useState)("");
773
+ var VariableCreation = ({ onGoBack, onClose }) => {
774
+ const { icon: VariableIcon, valueField: ValueField, variableType, propTypeUtil } = useVariableType();
775
+ const { setValue: setVariable, path } = (0, import_editor_controls2.useBoundProp)(propTypeUtil);
776
+ const initialValue = useInitialValue();
777
+ const [value, setValue] = (0, import_react6.useState)(initialValue);
778
+ const [label, setLabel] = (0, import_react6.useState)("");
779
+ const [errorMessage, setErrorMessage] = (0, import_react6.useState)("");
780
+ const { labelFieldError, setLabelFieldError } = useLabelError();
497
781
  const resetFields = () => {
498
- setColor("");
782
+ setValue("");
499
783
  setLabel("");
784
+ setErrorMessage("");
500
785
  };
501
786
  const closePopover = () => {
502
787
  resetFields();
503
788
  onClose();
504
789
  };
505
- const handleCreate = () => {
790
+ const handleCreateAndTrack = () => {
506
791
  createVariable({
507
- value: color,
792
+ value,
508
793
  label,
509
- type: colorVariablePropTypeUtil.key
794
+ type: propTypeUtil.key
510
795
  }).then((key) => {
511
796
  setVariable(key);
512
797
  closePopover();
798
+ }).catch((error) => {
799
+ const mappedError = mapServerError(error);
800
+ if (mappedError && "label" === mappedError.field) {
801
+ setLabel("");
802
+ setLabelFieldError({
803
+ value: label,
804
+ message: mappedError.message
805
+ });
806
+ return;
807
+ }
808
+ setErrorMessage(ERROR_MESSAGES.UNEXPECTED_ERROR);
809
+ });
810
+ trackVariableEvent({
811
+ varType: variableType,
812
+ controlPath: path.join("."),
813
+ action: "save"
513
814
  });
514
815
  };
515
816
  const hasEmptyValue = () => {
516
- return "" === color.trim() || "" === label.trim();
817
+ return "" === value.trim() || "" === label.trim();
818
+ };
819
+ const hasErrors = () => {
820
+ return !!errorMessage;
517
821
  };
518
- const isSubmitDisabled = hasEmptyValue();
519
- return /* @__PURE__ */ React3.createElement(import_editor_editing_panel.PopoverScrollableContent, { height: "auto" }, /* @__PURE__ */ React3.createElement(
520
- import_editor_ui.PopoverHeader,
822
+ const isSubmitDisabled = hasEmptyValue() || hasErrors();
823
+ return /* @__PURE__ */ React6.createElement(import_editor_editing_panel2.PopoverBody, { height: "auto" }, /* @__PURE__ */ React6.createElement(
824
+ import_editor_ui2.PopoverHeader,
521
825
  {
522
- icon: /* @__PURE__ */ React3.createElement(React3.Fragment, null, onGoBack && /* @__PURE__ */ React3.createElement(import_ui4.IconButton, { size: SIZE, "aria-label": (0, import_i18n4.__)("Go Back", "elementor"), onClick: onGoBack }, /* @__PURE__ */ React3.createElement(import_icons.ArrowLeftIcon, { fontSize: SIZE })), /* @__PURE__ */ React3.createElement(import_icons.BrushIcon, { fontSize: SIZE })),
523
- title: (0, import_i18n4.__)("Create variable", "elementor"),
826
+ icon: /* @__PURE__ */ React6.createElement(React6.Fragment, null, onGoBack && /* @__PURE__ */ React6.createElement(import_ui6.IconButton, { size: SIZE, "aria-label": (0, import_i18n6.__)("Go Back", "elementor"), onClick: onGoBack }, /* @__PURE__ */ React6.createElement(import_icons2.ArrowLeftIcon, { fontSize: SIZE })), /* @__PURE__ */ React6.createElement(VariableIcon, { fontSize: SIZE })),
827
+ title: (0, import_i18n6.__)("Create variable", "elementor"),
524
828
  onClose: closePopover
525
829
  }
526
- ), /* @__PURE__ */ React3.createElement(import_ui4.Divider, null), /* @__PURE__ */ React3.createElement(import_editor_controls.PopoverContent, { p: 2 }, /* @__PURE__ */ React3.createElement(LabelField, { value: label, onChange: setLabel }), /* @__PURE__ */ React3.createElement(ColorField, { value: color, onChange: setColor })), /* @__PURE__ */ React3.createElement(import_ui4.CardActions, { sx: { pt: 0.5, pb: 1 } }, /* @__PURE__ */ React3.createElement(import_ui4.Button, { size: "small", variant: "contained", disabled: isSubmitDisabled, onClick: handleCreate }, (0, import_i18n4.__)("Create", "elementor"))));
830
+ ), /* @__PURE__ */ React6.createElement(import_ui6.Divider, null), /* @__PURE__ */ React6.createElement(import_editor_controls2.PopoverContent, { p: 2 }, /* @__PURE__ */ React6.createElement(
831
+ LabelField,
832
+ {
833
+ value: label,
834
+ error: labelFieldError,
835
+ onChange: (newValue) => {
836
+ setLabel(newValue);
837
+ setErrorMessage("");
838
+ }
839
+ }
840
+ ), /* @__PURE__ */ React6.createElement(
841
+ ValueField,
842
+ {
843
+ value,
844
+ onChange: (newValue) => {
845
+ setValue(newValue);
846
+ setErrorMessage("");
847
+ }
848
+ }
849
+ ), errorMessage && /* @__PURE__ */ React6.createElement(import_ui6.FormHelperText, { error: true }, errorMessage)), /* @__PURE__ */ React6.createElement(import_ui6.CardActions, { sx: { pt: 0.5, pb: 1 } }, /* @__PURE__ */ React6.createElement(import_ui6.Button, { size: "small", variant: "contained", disabled: isSubmitDisabled, onClick: handleCreateAndTrack }, (0, import_i18n6.__)("Create", "elementor"))));
527
850
  };
528
851
 
529
- // src/components/color-variable-edit.tsx
530
- var React5 = __toESM(require("react"));
531
- var import_react6 = require("react");
532
- var import_editor_controls2 = require("@elementor/editor-controls");
533
- var import_editor_editing_panel2 = require("@elementor/editor-editing-panel");
534
- var import_editor_ui2 = require("@elementor/editor-ui");
535
- var import_icons3 = require("@elementor/icons");
536
- var import_ui6 = require("@elementor/ui");
537
- var import_i18n6 = require("@wordpress/i18n");
538
-
539
- // src/components/ui/delete-confirmation-dialog.tsx
540
- var React4 = __toESM(require("react"));
541
- var import_icons2 = require("@elementor/icons");
542
- var import_ui5 = require("@elementor/ui");
543
- var import_i18n5 = require("@wordpress/i18n");
852
+ // src/components/variable-edit.tsx
853
+ var React9 = __toESM(require("react"));
854
+ var import_react8 = require("react");
855
+ var import_editor_controls3 = require("@elementor/editor-controls");
856
+ var import_editor_current_user2 = require("@elementor/editor-current-user");
857
+ var import_editor_editing_panel3 = require("@elementor/editor-editing-panel");
858
+ var import_editor_ui3 = require("@elementor/editor-ui");
859
+ var import_icons5 = require("@elementor/icons");
860
+ var import_ui9 = require("@elementor/ui");
861
+ var import_i18n9 = require("@wordpress/i18n");
862
+
863
+ // src/components/ui/delete-confirmation-dialog.tsx
864
+ var React7 = __toESM(require("react"));
865
+ var import_icons3 = require("@elementor/icons");
866
+ var import_ui7 = require("@elementor/ui");
867
+ var import_i18n7 = require("@wordpress/i18n");
544
868
  var TITLE_ID = "delete-variable-dialog";
545
869
  var DeleteConfirmationDialog = ({
546
870
  open,
@@ -548,30 +872,102 @@ var DeleteConfirmationDialog = ({
548
872
  closeDialog,
549
873
  onConfirm
550
874
  }) => {
551
- return /* @__PURE__ */ React4.createElement(import_ui5.Dialog, { open, onClose: closeDialog, "aria-labelledby": TITLE_ID, maxWidth: "xs" }, /* @__PURE__ */ React4.createElement(import_ui5.DialogTitle, { id: TITLE_ID, display: "flex", alignItems: "center", gap: 1, sx: { lineHeight: 1 } }, /* @__PURE__ */ React4.createElement(import_icons2.AlertOctagonFilledIcon, { color: "error" }), (0, import_i18n5.__)("Delete Variable", "elementor")), /* @__PURE__ */ React4.createElement(import_ui5.DialogContent, null, /* @__PURE__ */ React4.createElement(import_ui5.DialogContentText, { variant: "body2", color: "textPrimary" }, (0, import_i18n5.__)("You are about to delete", "elementor"), /* @__PURE__ */ React4.createElement(import_ui5.Typography, { variant: "subtitle2", component: "span" }, "\xA0", label, "\xA0"), (0, import_i18n5.__)(
552
- "Variable. Note that its value is still being used anywhere on your site where it was connected to the variable.",
875
+ return /* @__PURE__ */ React7.createElement(import_ui7.Dialog, { open, onClose: closeDialog, "aria-labelledby": TITLE_ID, maxWidth: "xs" }, /* @__PURE__ */ React7.createElement(import_ui7.DialogTitle, { id: TITLE_ID, display: "flex", alignItems: "center", gap: 1, sx: { lineHeight: 1 } }, /* @__PURE__ */ React7.createElement(import_icons3.AlertOctagonFilledIcon, { color: "error" }), (0, import_i18n7.__)("Delete this variable?", "elementor")), /* @__PURE__ */ React7.createElement(import_ui7.DialogContent, null, /* @__PURE__ */ React7.createElement(import_ui7.DialogContentText, { variant: "body2", color: "textPrimary" }, (0, import_i18n7.__)("All elements using", "elementor"), /* @__PURE__ */ React7.createElement(import_ui7.Typography, { variant: "subtitle2", component: "span" }, "\xA0", label, "\xA0"), (0, import_i18n7.__)("will keep their current values, but the variable itself will be removed.", "elementor"))), /* @__PURE__ */ React7.createElement(import_ui7.DialogActions, null, /* @__PURE__ */ React7.createElement(import_ui7.Button, { color: "secondary", onClick: closeDialog }, (0, import_i18n7.__)("Not now", "elementor")), /* @__PURE__ */ React7.createElement(import_ui7.Button, { variant: "contained", color: "error", onClick: onConfirm }, (0, import_i18n7.__)("Delete", "elementor"))));
876
+ };
877
+
878
+ // src/components/ui/edit-confirmation-dialog.tsx
879
+ var React8 = __toESM(require("react"));
880
+ var import_react7 = require("react");
881
+ var import_icons4 = require("@elementor/icons");
882
+ var import_ui8 = require("@elementor/ui");
883
+ var import_i18n8 = require("@wordpress/i18n");
884
+ var EDIT_CONFIRMATION_DIALOG_ID = "edit-confirmation-dialog";
885
+ var EditConfirmationDialog = ({
886
+ closeDialog,
887
+ onConfirm,
888
+ onSuppressMessage
889
+ }) => {
890
+ const [dontShowAgain, setDontShowAgain] = (0, import_react7.useState)(false);
891
+ const handleSave = () => {
892
+ if (dontShowAgain) {
893
+ onSuppressMessage?.();
894
+ }
895
+ onConfirm?.();
896
+ };
897
+ return /* @__PURE__ */ React8.createElement(import_ui8.Dialog, { open: true, onClose: closeDialog, maxWidth: "xs" }, /* @__PURE__ */ React8.createElement(import_ui8.DialogTitle, { display: "flex", alignItems: "center", gap: 1 }, /* @__PURE__ */ React8.createElement(import_icons4.AlertTriangleFilledIcon, { color: "secondary" }), (0, import_i18n8.__)("Changes to variables go live right away.", "elementor")), /* @__PURE__ */ React8.createElement(import_ui8.DialogContent, null, /* @__PURE__ */ React8.createElement(import_ui8.DialogContentText, { variant: "body2", color: "textPrimary" }, (0, import_i18n8.__)(
898
+ "Don't worry - all other changes you make will wait until you publish your site.",
553
899
  "elementor"
554
- ))), /* @__PURE__ */ React4.createElement(import_ui5.DialogActions, null, /* @__PURE__ */ React4.createElement(import_ui5.Button, { color: "secondary", onClick: closeDialog }, (0, import_i18n5.__)("Cancel", "elementor")), /* @__PURE__ */ React4.createElement(import_ui5.Button, { variant: "contained", color: "error", onClick: onConfirm }, (0, import_i18n5.__)("Delete", "elementor"))));
900
+ ))), /* @__PURE__ */ React8.createElement(import_ui8.DialogActions, { sx: { justifyContent: "space-between", alignItems: "center" } }, /* @__PURE__ */ React8.createElement(
901
+ import_ui8.FormControlLabel,
902
+ {
903
+ control: /* @__PURE__ */ React8.createElement(
904
+ import_ui8.Checkbox,
905
+ {
906
+ checked: dontShowAgain,
907
+ onChange: (event) => setDontShowAgain(event.target.checked),
908
+ size: "small"
909
+ }
910
+ ),
911
+ label: /* @__PURE__ */ React8.createElement(import_ui8.Typography, { variant: "body2" }, (0, import_i18n8.__)("Don't show me again", "elementor"))
912
+ }
913
+ ), /* @__PURE__ */ React8.createElement("div", null, /* @__PURE__ */ React8.createElement(import_ui8.Button, { color: "secondary", onClick: closeDialog }, (0, import_i18n8.__)("Keep editing", "elementor")), /* @__PURE__ */ React8.createElement(import_ui8.Button, { variant: "contained", color: "secondary", onClick: handleSave, sx: { ml: 1 } }, (0, import_i18n8.__)("Save", "elementor")))));
555
914
  };
556
915
 
557
- // src/components/color-variable-edit.tsx
916
+ // src/components/variable-edit.tsx
558
917
  var SIZE2 = "tiny";
559
- var ColorVariableEdit = ({ onClose, onGoBack, onSubmit, editId }) => {
560
- const { setValue: notifyBoundPropChange, value: assignedValue } = (0, import_editor_controls2.useBoundProp)(colorVariablePropTypeUtil);
561
- const [deleteConfirmation, setDeleteConfirmation] = (0, import_react6.useState)(false);
918
+ var VariableEdit = ({ onClose, onGoBack, onSubmit, editId }) => {
919
+ const { icon: VariableIcon, valueField: ValueField, variableType, propTypeUtil } = useVariableType();
920
+ const { setValue: notifyBoundPropChange, value: assignedValue } = (0, import_editor_controls3.useBoundProp)(propTypeUtil);
921
+ const [isMessageSuppressed, suppressMessage] = (0, import_editor_current_user2.useSuppressedMessage)(EDIT_CONFIRMATION_DIALOG_ID);
922
+ const [deleteConfirmation, setDeleteConfirmation] = (0, import_react8.useState)(false);
923
+ const [editConfirmation, setEditConfirmation] = (0, import_react8.useState)(false);
924
+ const [errorMessage, setErrorMessage] = (0, import_react8.useState)("");
925
+ const { labelFieldError, setLabelFieldError } = useLabelError();
562
926
  const variable = useVariable(editId);
563
927
  if (!variable) {
564
- throw new Error(`Global color variable not found`);
928
+ throw new Error(`Global ${variableType} variable not found`);
565
929
  }
566
- const [color, setColor] = (0, import_react6.useState)(variable.value);
567
- const [label, setLabel] = (0, import_react6.useState)(variable.label);
930
+ const userPermissions = usePermissions();
931
+ const [value, setValue] = (0, import_react8.useState)(variable.value);
932
+ const [label, setLabel] = (0, import_react8.useState)(variable.label);
933
+ (0, import_react8.useEffect)(() => {
934
+ styleVariablesRepository.update({
935
+ [editId]: {
936
+ ...variable,
937
+ value
938
+ }
939
+ });
940
+ return () => {
941
+ styleVariablesRepository.update({
942
+ [editId]: { ...variable }
943
+ });
944
+ };
945
+ }, [editId, value, variable]);
568
946
  const handleUpdate = () => {
947
+ if (isMessageSuppressed) {
948
+ handleSaveVariable();
949
+ } else {
950
+ setEditConfirmation(true);
951
+ }
952
+ };
953
+ const handleSaveVariable = () => {
569
954
  updateVariable(editId, {
570
- value: color,
955
+ value,
571
956
  label
572
957
  }).then(() => {
573
958
  maybeTriggerBoundPropChange();
574
959
  onSubmit?.();
960
+ }).catch((error) => {
961
+ const mappedError = mapServerError(error);
962
+ if (mappedError && "label" === mappedError.field) {
963
+ setLabel("");
964
+ setLabelFieldError({
965
+ value: label,
966
+ message: mappedError.message
967
+ });
968
+ return;
969
+ }
970
+ setErrorMessage(ERROR_MESSAGES.UNEXPECTED_ERROR);
575
971
  });
576
972
  };
577
973
  const handleDelete = () => {
@@ -591,43 +987,70 @@ var ColorVariableEdit = ({ onClose, onGoBack, onSubmit, editId }) => {
591
987
  const closeDeleteDialog = () => () => {
592
988
  setDeleteConfirmation(false);
593
989
  };
990
+ const closeEditDialog = () => () => {
991
+ setEditConfirmation(false);
992
+ };
594
993
  const actions = [];
595
- actions.push(
596
- /* @__PURE__ */ React5.createElement(
597
- import_ui6.IconButton,
598
- {
599
- key: "delete",
600
- size: SIZE2,
601
- "aria-label": (0, import_i18n6.__)("Delete", "elementor"),
602
- onClick: handleDeleteConfirmation
603
- },
604
- /* @__PURE__ */ React5.createElement(import_icons3.TrashIcon, { fontSize: SIZE2 })
605
- )
606
- );
994
+ if (userPermissions.canDelete()) {
995
+ actions.push(
996
+ /* @__PURE__ */ React9.createElement(
997
+ import_ui9.IconButton,
998
+ {
999
+ key: "delete",
1000
+ size: SIZE2,
1001
+ "aria-label": (0, import_i18n9.__)("Delete", "elementor"),
1002
+ onClick: handleDeleteConfirmation
1003
+ },
1004
+ /* @__PURE__ */ React9.createElement(import_icons5.TrashIcon, { fontSize: SIZE2 })
1005
+ )
1006
+ );
1007
+ }
607
1008
  const hasEmptyValues = () => {
608
- return !color.trim() || !label.trim();
1009
+ return !value.trim() || !label.trim();
609
1010
  };
610
1011
  const noValueChanged = () => {
611
- return color === variable.value && label === variable.label;
1012
+ return value === variable.value && label === variable.label;
612
1013
  };
613
- const isSubmitDisabled = noValueChanged() || hasEmptyValues();
614
- return /* @__PURE__ */ React5.createElement(React5.Fragment, null, /* @__PURE__ */ React5.createElement(import_editor_editing_panel2.PopoverScrollableContent, { height: "auto" }, /* @__PURE__ */ React5.createElement(
615
- import_editor_ui2.PopoverHeader,
1014
+ const hasErrors = () => {
1015
+ return !!errorMessage;
1016
+ };
1017
+ const isSubmitDisabled = noValueChanged() || hasEmptyValues() || hasErrors();
1018
+ return /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(import_editor_editing_panel3.PopoverBody, { height: "auto" }, /* @__PURE__ */ React9.createElement(
1019
+ import_editor_ui3.PopoverHeader,
616
1020
  {
617
- title: (0, import_i18n6.__)("Edit variable", "elementor"),
1021
+ title: (0, import_i18n9.__)("Edit variable", "elementor"),
618
1022
  onClose,
619
- icon: /* @__PURE__ */ React5.createElement(React5.Fragment, null, onGoBack && /* @__PURE__ */ React5.createElement(
620
- import_ui6.IconButton,
1023
+ icon: /* @__PURE__ */ React9.createElement(React9.Fragment, null, onGoBack && /* @__PURE__ */ React9.createElement(
1024
+ import_ui9.IconButton,
621
1025
  {
622
1026
  size: SIZE2,
623
- "aria-label": (0, import_i18n6.__)("Go Back", "elementor"),
1027
+ "aria-label": (0, import_i18n9.__)("Go Back", "elementor"),
624
1028
  onClick: onGoBack
625
1029
  },
626
- /* @__PURE__ */ React5.createElement(import_icons3.ArrowLeftIcon, { fontSize: SIZE2 })
627
- ), /* @__PURE__ */ React5.createElement(import_icons3.BrushIcon, { fontSize: SIZE2 })),
1030
+ /* @__PURE__ */ React9.createElement(import_icons5.ArrowLeftIcon, { fontSize: SIZE2 })
1031
+ ), /* @__PURE__ */ React9.createElement(VariableIcon, { fontSize: SIZE2 })),
628
1032
  actions
629
1033
  }
630
- ), /* @__PURE__ */ React5.createElement(import_ui6.Divider, null), /* @__PURE__ */ React5.createElement(import_editor_controls2.PopoverContent, { p: 2 }, /* @__PURE__ */ React5.createElement(LabelField, { value: label, onChange: setLabel }), /* @__PURE__ */ React5.createElement(ColorField, { value: color, onChange: setColor })), /* @__PURE__ */ React5.createElement(import_ui6.CardActions, { sx: { pt: 0.5, pb: 1 } }, /* @__PURE__ */ React5.createElement(import_ui6.Button, { size: "small", variant: "contained", disabled: isSubmitDisabled, onClick: handleUpdate }, (0, import_i18n6.__)("Save", "elementor")))), deleteConfirmation && /* @__PURE__ */ React5.createElement(
1034
+ ), /* @__PURE__ */ React9.createElement(import_ui9.Divider, null), /* @__PURE__ */ React9.createElement(import_editor_controls3.PopoverContent, { p: 2 }, /* @__PURE__ */ React9.createElement(
1035
+ LabelField,
1036
+ {
1037
+ value: label,
1038
+ error: labelFieldError,
1039
+ onChange: (newValue) => {
1040
+ setLabel(newValue);
1041
+ setErrorMessage("");
1042
+ }
1043
+ }
1044
+ ), /* @__PURE__ */ React9.createElement(
1045
+ ValueField,
1046
+ {
1047
+ value,
1048
+ onChange: (newValue) => {
1049
+ setValue(newValue);
1050
+ setErrorMessage("");
1051
+ }
1052
+ }
1053
+ ), errorMessage && /* @__PURE__ */ React9.createElement(import_ui9.FormHelperText, { error: true }, errorMessage)), /* @__PURE__ */ React9.createElement(import_ui9.CardActions, { sx: { pt: 0.5, pb: 1 } }, /* @__PURE__ */ React9.createElement(import_ui9.Button, { size: "small", variant: "contained", disabled: isSubmitDisabled, onClick: handleUpdate }, (0, import_i18n9.__)("Save", "elementor")))), deleteConfirmation && /* @__PURE__ */ React9.createElement(
631
1054
  DeleteConfirmationDialog,
632
1055
  {
633
1056
  open: true,
@@ -635,30 +1058,37 @@ var ColorVariableEdit = ({ onClose, onGoBack, onSubmit, editId }) => {
635
1058
  onConfirm: handleDelete,
636
1059
  closeDialog: closeDeleteDialog()
637
1060
  }
1061
+ ), editConfirmation && !isMessageSuppressed && /* @__PURE__ */ React9.createElement(
1062
+ EditConfirmationDialog,
1063
+ {
1064
+ closeDialog: closeEditDialog(),
1065
+ onConfirm: handleSaveVariable,
1066
+ onSuppressMessage: suppressMessage
1067
+ }
638
1068
  ));
639
1069
  };
640
1070
 
641
- // src/components/color-variables-selection.tsx
642
- var React9 = __toESM(require("react"));
643
- var import_react7 = require("react");
644
- var import_editor_controls3 = require("@elementor/editor-controls");
645
- var import_editor_editing_panel3 = require("@elementor/editor-editing-panel");
646
- var import_editor_ui4 = require("@elementor/editor-ui");
647
- var import_icons5 = require("@elementor/icons");
648
- var import_ui11 = require("@elementor/ui");
649
- var import_i18n10 = require("@wordpress/i18n");
1071
+ // src/components/variables-selection.tsx
1072
+ var React13 = __toESM(require("react"));
1073
+ var import_react9 = require("react");
1074
+ var import_editor_controls4 = require("@elementor/editor-controls");
1075
+ var import_editor_editing_panel4 = require("@elementor/editor-editing-panel");
1076
+ var import_editor_ui5 = require("@elementor/editor-ui");
1077
+ var import_icons7 = require("@elementor/icons");
1078
+ var import_ui14 = require("@elementor/ui");
1079
+ var import_i18n13 = require("@wordpress/i18n");
650
1080
 
651
1081
  // src/components/ui/menu-item-content.tsx
652
- var React6 = __toESM(require("react"));
653
- var import_editor_ui3 = require("@elementor/editor-ui");
654
- var import_icons4 = require("@elementor/icons");
655
- var import_ui7 = require("@elementor/ui");
656
- var import_i18n7 = require("@wordpress/i18n");
1082
+ var React10 = __toESM(require("react"));
1083
+ var import_editor_ui4 = require("@elementor/editor-ui");
1084
+ var import_icons6 = require("@elementor/icons");
1085
+ var import_ui10 = require("@elementor/ui");
1086
+ var import_i18n10 = require("@wordpress/i18n");
657
1087
  var SIZE3 = "tiny";
658
1088
  var MenuItemContent = ({ item }) => {
659
1089
  const onEdit = item.onEdit;
660
- return /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(import_ui7.ListItemIcon, null, item.icon), /* @__PURE__ */ React6.createElement(
661
- import_ui7.Box,
1090
+ return /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(import_ui10.ListItemIcon, null, item.icon), /* @__PURE__ */ React10.createElement(
1091
+ import_ui10.Box,
662
1092
  {
663
1093
  sx: {
664
1094
  flex: 1,
@@ -668,49 +1098,49 @@ var MenuItemContent = ({ item }) => {
668
1098
  gap: 1
669
1099
  }
670
1100
  },
671
- /* @__PURE__ */ React6.createElement(
672
- import_editor_ui3.EllipsisWithTooltip,
1101
+ /* @__PURE__ */ React10.createElement(
1102
+ import_editor_ui4.EllipsisWithTooltip,
673
1103
  {
674
1104
  title: item.label || item.value,
675
- as: import_ui7.Typography,
1105
+ as: import_ui10.Typography,
676
1106
  variant: "caption",
677
1107
  color: "text.primary",
678
1108
  sx: { marginTop: "1px", lineHeight: "2" },
679
1109
  maxWidth: "50%"
680
1110
  }
681
1111
  ),
682
- item.secondaryText && /* @__PURE__ */ React6.createElement(
683
- import_editor_ui3.EllipsisWithTooltip,
1112
+ item.secondaryText && /* @__PURE__ */ React10.createElement(
1113
+ import_editor_ui4.EllipsisWithTooltip,
684
1114
  {
685
1115
  title: item.secondaryText,
686
- as: import_ui7.Typography,
1116
+ as: import_ui10.Typography,
687
1117
  variant: "caption",
688
1118
  color: "text.tertiary",
689
1119
  sx: { marginTop: "1px", lineHeight: "1" },
690
1120
  maxWidth: "50%"
691
1121
  }
692
1122
  )
693
- ), !!onEdit && /* @__PURE__ */ React6.createElement(
694
- import_ui7.IconButton,
1123
+ ), !!onEdit && /* @__PURE__ */ React10.createElement(
1124
+ import_ui10.IconButton,
695
1125
  {
696
1126
  sx: { mx: 1, opacity: "0" },
697
1127
  onClick: (e) => {
698
1128
  e.stopPropagation();
699
1129
  onEdit(item.value);
700
1130
  },
701
- "aria-label": (0, import_i18n7.__)("Edit", "elementor")
1131
+ "aria-label": (0, import_i18n10.__)("Edit", "elementor")
702
1132
  },
703
- /* @__PURE__ */ React6.createElement(import_icons4.EditIcon, { color: "action", fontSize: SIZE3 })
1133
+ /* @__PURE__ */ React10.createElement(import_icons6.EditIcon, { color: "action", fontSize: SIZE3 })
704
1134
  ));
705
1135
  };
706
1136
 
707
1137
  // src/components/ui/no-search-results.tsx
708
- var React7 = __toESM(require("react"));
709
- var import_ui8 = require("@elementor/ui");
710
- var import_i18n8 = require("@wordpress/i18n");
1138
+ var React11 = __toESM(require("react"));
1139
+ var import_ui11 = require("@elementor/ui");
1140
+ var import_i18n11 = require("@wordpress/i18n");
711
1141
  var NoSearchResults = ({ searchValue, onClear, icon }) => {
712
- return /* @__PURE__ */ React7.createElement(
713
- import_ui8.Stack,
1142
+ return /* @__PURE__ */ React11.createElement(
1143
+ import_ui11.Stack,
714
1144
  {
715
1145
  gap: 1,
716
1146
  alignItems: "center",
@@ -721,34 +1151,53 @@ var NoSearchResults = ({ searchValue, onClear, icon }) => {
721
1151
  sx: { pb: 3.5 }
722
1152
  },
723
1153
  icon,
724
- /* @__PURE__ */ React7.createElement(import_ui8.Typography, { align: "center", variant: "subtitle2" }, (0, import_i18n8.__)("Sorry, nothing matched", "elementor"), /* @__PURE__ */ React7.createElement("br", null), "\u201C", searchValue, "\u201D."),
725
- /* @__PURE__ */ React7.createElement(import_ui8.Typography, { align: "center", variant: "caption", sx: { display: "flex", flexDirection: "column" } }, (0, import_i18n8.__)("Try something else.", "elementor"), /* @__PURE__ */ React7.createElement(import_ui8.Link, { color: "text.secondary", variant: "caption", component: "button", onClick: onClear }, (0, import_i18n8.__)("Clear & try again", "elementor")))
1154
+ /* @__PURE__ */ React11.createElement(import_ui11.Typography, { align: "center", variant: "subtitle2" }, (0, import_i18n11.__)("Sorry, nothing matched", "elementor"), /* @__PURE__ */ React11.createElement("br", null), "\u201C", searchValue, "\u201D."),
1155
+ /* @__PURE__ */ React11.createElement(import_ui11.Typography, { align: "center", variant: "caption", sx: { display: "flex", flexDirection: "column" } }, (0, import_i18n11.__)("Try something else.", "elementor"), /* @__PURE__ */ React11.createElement(import_ui11.Link, { color: "text.secondary", variant: "caption", component: "button", onClick: onClear }, (0, import_i18n11.__)("Clear & try again", "elementor")))
726
1156
  );
727
1157
  };
728
1158
 
729
1159
  // src/components/ui/no-variables.tsx
730
- var React8 = __toESM(require("react"));
731
- var import_ui9 = require("@elementor/ui");
732
- var import_i18n9 = require("@wordpress/i18n");
733
- var NoVariables = ({ icon, title, onAdd }) => /* @__PURE__ */ React8.createElement(
734
- import_ui9.Stack,
735
- {
736
- gap: 1,
737
- alignItems: "center",
738
- justifyContent: "center",
739
- height: "100%",
740
- color: "text.secondary",
741
- sx: { p: 2.5, pb: 5.5 }
742
- },
743
- icon,
744
- /* @__PURE__ */ React8.createElement(import_ui9.Typography, { align: "center", variant: "subtitle2" }, title),
745
- /* @__PURE__ */ React8.createElement(import_ui9.Typography, { align: "center", variant: "caption", maxWidth: "180px" }, (0, import_i18n9.__)("Variables are saved attributes that you can apply anywhere on your site.", "elementor")),
746
- onAdd && /* @__PURE__ */ React8.createElement(import_ui9.Button, { variant: "outlined", color: "secondary", size: "small", onClick: onAdd }, (0, import_i18n9.__)("Create a variable", "elementor"))
747
- );
1160
+ var React12 = __toESM(require("react"));
1161
+ var import_ui12 = require("@elementor/ui");
1162
+ var import_i18n12 = require("@wordpress/i18n");
1163
+ var NoVariables = ({ icon, title, onAdd }) => {
1164
+ const canAdd = usePermissions().canAdd();
1165
+ return /* @__PURE__ */ React12.createElement(
1166
+ import_ui12.Stack,
1167
+ {
1168
+ gap: 1,
1169
+ alignItems: "center",
1170
+ justifyContent: "center",
1171
+ height: "100%",
1172
+ color: "text.secondary",
1173
+ sx: { p: 2.5, pb: 5.5 }
1174
+ },
1175
+ icon,
1176
+ canAdd ? /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(
1177
+ NoVariablesContent,
1178
+ {
1179
+ title: title || (0, import_i18n12.__)("Create your first variable", "elementor"),
1180
+ message: (0, import_i18n12.__)(
1181
+ "Variables are saved attributes that you can apply anywhere on your site.",
1182
+ "elementor"
1183
+ )
1184
+ }
1185
+ ), onAdd && /* @__PURE__ */ React12.createElement(import_ui12.Button, { variant: "outlined", color: "secondary", size: "small", onClick: onAdd }, (0, import_i18n12.__)("Create a variable", "elementor"))) : /* @__PURE__ */ React12.createElement(
1186
+ NoVariablesContent,
1187
+ {
1188
+ title: (0, import_i18n12.__)("There are no variables", "elementor"),
1189
+ message: (0, import_i18n12.__)("With your current role, you can only connect and detach variables.", "elementor")
1190
+ }
1191
+ )
1192
+ );
1193
+ };
1194
+ function NoVariablesContent({ title, message }) {
1195
+ return /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(import_ui12.Typography, { align: "center", variant: "subtitle2" }, title), /* @__PURE__ */ React12.createElement(import_ui12.Typography, { align: "center", variant: "caption", maxWidth: "180px" }, message));
1196
+ }
748
1197
 
749
1198
  // src/components/ui/styled-menu-list.tsx
750
- var import_ui10 = require("@elementor/ui");
751
- var VariablesStyledMenuList = (0, import_ui10.styled)(import_ui10.MenuList)(({ theme }) => ({
1199
+ var import_ui13 = require("@elementor/ui");
1200
+ var VariablesStyledMenuList = (0, import_ui13.styled)(import_ui13.MenuList)(({ theme }) => ({
752
1201
  "& > li": {
753
1202
  height: 32,
754
1203
  width: "100%",
@@ -778,38 +1227,53 @@ var VariablesStyledMenuList = (0, import_ui10.styled)(import_ui10.MenuList)(({ t
778
1227
  position: "relative"
779
1228
  }));
780
1229
 
781
- // src/components/color-variables-selection.tsx
1230
+ // src/components/variables-selection.tsx
782
1231
  var SIZE4 = "tiny";
783
- var ColorVariablesSelection = ({ closePopover, onAdd, onEdit, onSettings }) => {
784
- const { value: variable, setValue: setVariable } = (0, import_editor_controls3.useBoundProp)(colorVariablePropTypeUtil);
785
- const [searchValue, setSearchValue] = (0, import_react7.useState)("");
1232
+ var VariablesSelection = ({ closePopover, onAdd, onEdit, onSettings }) => {
1233
+ const { icon: VariableIcon, startIcon, variableType, propTypeUtil } = useVariableType();
1234
+ const { value: variable, setValue: setVariable, path } = (0, import_editor_controls4.useBoundProp)(propTypeUtil);
1235
+ const [searchValue, setSearchValue] = (0, import_react9.useState)("");
786
1236
  const {
787
1237
  list: variables,
788
1238
  hasMatches: hasSearchResults,
789
1239
  isSourceNotEmpty: hasVariables
790
- } = useFilteredVariables(searchValue, colorVariablePropTypeUtil.key);
791
- const handleSetColorVariable = (key) => {
1240
+ } = useFilteredVariables(searchValue, propTypeUtil.key);
1241
+ const handleSetVariable = (key) => {
792
1242
  setVariable(key);
1243
+ trackVariableEvent({
1244
+ varType: variableType,
1245
+ controlPath: path.join("."),
1246
+ action: "connect"
1247
+ });
793
1248
  closePopover();
794
1249
  };
1250
+ const onAddAndTrack = () => {
1251
+ onAdd?.();
1252
+ trackVariableEvent({
1253
+ varType: variableType,
1254
+ controlPath: path.join("."),
1255
+ action: "add"
1256
+ });
1257
+ };
795
1258
  const actions = [];
796
1259
  if (onAdd) {
797
1260
  actions.push(
798
- /* @__PURE__ */ React9.createElement(import_ui11.IconButton, { key: "add", size: SIZE4, onClick: onAdd }, /* @__PURE__ */ React9.createElement(import_icons5.PlusIcon, { fontSize: SIZE4 }))
1261
+ /* @__PURE__ */ React13.createElement(import_ui14.IconButton, { key: "add", size: SIZE4, onClick: onAddAndTrack }, /* @__PURE__ */ React13.createElement(import_icons7.PlusIcon, { fontSize: SIZE4 }))
799
1262
  );
800
1263
  }
801
1264
  if (onSettings) {
802
1265
  actions.push(
803
- /* @__PURE__ */ React9.createElement(import_ui11.IconButton, { key: "settings", size: SIZE4, onClick: onSettings }, /* @__PURE__ */ React9.createElement(import_icons5.SettingsIcon, { fontSize: SIZE4 }))
1266
+ /* @__PURE__ */ React13.createElement(import_ui14.IconButton, { key: "settings", size: SIZE4, onClick: onSettings }, /* @__PURE__ */ React13.createElement(import_icons7.SettingsIcon, { fontSize: SIZE4 }))
804
1267
  );
805
1268
  }
1269
+ const StartIcon = startIcon || (() => /* @__PURE__ */ React13.createElement(VariableIcon, { fontSize: SIZE4 }));
806
1270
  const items = variables.map(({ value, label, key }) => ({
807
1271
  type: "item",
808
1272
  value: key,
809
1273
  label,
810
- icon: /* @__PURE__ */ React9.createElement(ColorIndicator, { size: "inherit", component: "span", value }),
1274
+ icon: /* @__PURE__ */ React13.createElement(StartIcon, { value }),
811
1275
  secondaryText: value,
812
- onEdit: () => onEdit?.(key)
1276
+ onEdit: onEdit ? () => onEdit?.(key) : void 0
813
1277
  }));
814
1278
  const handleSearch = (search) => {
815
1279
  setSearchValue(search);
@@ -817,737 +1281,711 @@ var ColorVariablesSelection = ({ closePopover, onAdd, onEdit, onSettings }) => {
817
1281
  const handleClearSearch = () => {
818
1282
  setSearchValue("");
819
1283
  };
820
- return /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(
821
- import_editor_ui4.PopoverHeader,
1284
+ const noVariableTitle = (0, import_i18n13.sprintf)(
1285
+ /* translators: %s: Variable Type. */
1286
+ (0, import_i18n13.__)("Create your first %s variable", "elementor"),
1287
+ variableType
1288
+ );
1289
+ return /* @__PURE__ */ React13.createElement(import_editor_editing_panel4.PopoverBody, null, /* @__PURE__ */ React13.createElement(
1290
+ import_editor_ui5.PopoverHeader,
822
1291
  {
823
- title: (0, import_i18n10.__)("Variables", "elementor"),
824
- icon: /* @__PURE__ */ React9.createElement(import_icons5.ColorFilterIcon, { fontSize: SIZE4 }),
1292
+ title: (0, import_i18n13.__)("Variables", "elementor"),
1293
+ icon: /* @__PURE__ */ React13.createElement(import_icons7.ColorFilterIcon, { fontSize: SIZE4 }),
825
1294
  onClose: closePopover,
826
1295
  actions
827
1296
  }
828
- ), hasVariables && /* @__PURE__ */ React9.createElement(
829
- import_editor_ui4.PopoverSearch,
1297
+ ), hasVariables && /* @__PURE__ */ React13.createElement(
1298
+ import_editor_ui5.PopoverSearch,
830
1299
  {
831
1300
  value: searchValue,
832
1301
  onSearch: handleSearch,
833
- placeholder: (0, import_i18n10.__)("Search", "elementor")
1302
+ placeholder: (0, import_i18n13.__)("Search", "elementor")
834
1303
  }
835
- ), /* @__PURE__ */ React9.createElement(import_ui11.Divider, null), /* @__PURE__ */ React9.createElement(import_editor_editing_panel3.PopoverScrollableContent, null, hasVariables && hasSearchResults && /* @__PURE__ */ React9.createElement(
836
- import_editor_ui4.PopoverMenuList,
1304
+ ), /* @__PURE__ */ React13.createElement(import_ui14.Divider, null), hasVariables && hasSearchResults && /* @__PURE__ */ React13.createElement(
1305
+ import_editor_ui5.PopoverMenuList,
837
1306
  {
838
1307
  items,
839
- onSelect: handleSetColorVariable,
1308
+ onSelect: handleSetVariable,
840
1309
  onClose: () => {
841
1310
  },
842
1311
  selectedValue: variable,
843
- "data-testid": "color-variables-list",
1312
+ "data-testid": `${variableType}-variables-list`,
844
1313
  menuListTemplate: VariablesStyledMenuList,
845
- menuItemContentTemplate: (item) => /* @__PURE__ */ React9.createElement(MenuItemContent, { item })
1314
+ menuItemContentTemplate: (item) => /* @__PURE__ */ React13.createElement(MenuItemContent, { item })
846
1315
  }
847
- ), !hasSearchResults && hasVariables && /* @__PURE__ */ React9.createElement(
1316
+ ), !hasSearchResults && hasVariables && /* @__PURE__ */ React13.createElement(
848
1317
  NoSearchResults,
849
1318
  {
850
1319
  searchValue,
851
1320
  onClear: handleClearSearch,
852
- icon: /* @__PURE__ */ React9.createElement(import_icons5.BrushIcon, { fontSize: "large" })
1321
+ icon: /* @__PURE__ */ React13.createElement(VariableIcon, { fontSize: "large" })
1322
+ }
1323
+ ), !hasVariables && /* @__PURE__ */ React13.createElement(NoVariables, { title: noVariableTitle, icon: /* @__PURE__ */ React13.createElement(VariableIcon, { fontSize: "large" }), onAdd }));
1324
+ };
1325
+
1326
+ // src/components/variable-selection-popover.tsx
1327
+ var VIEW_LIST = "list";
1328
+ var VIEW_ADD = "add";
1329
+ var VIEW_EDIT = "edit";
1330
+ var VariableSelectionPopover = ({ closePopover, propTypeKey, selectedVariable }) => {
1331
+ const [currentView, setCurrentView] = (0, import_react10.useState)(VIEW_LIST);
1332
+ const [editId, setEditId] = (0, import_react10.useState)("");
1333
+ const { open } = usePanelActions();
1334
+ const onSettingsAvailable = (0, import_editor_v1_adapters2.isExperimentActive)("e_variables_settings") ? () => {
1335
+ open();
1336
+ } : void 0;
1337
+ return /* @__PURE__ */ React14.createElement(VariableTypeProvider, { propTypeKey }, /* @__PURE__ */ React14.createElement(PopoverContentRefContextProvider, null, RenderView({
1338
+ propTypeKey,
1339
+ currentView,
1340
+ selectedVariable,
1341
+ editId,
1342
+ setEditId,
1343
+ setCurrentView,
1344
+ closePopover,
1345
+ onSettings: onSettingsAvailable
1346
+ })));
1347
+ };
1348
+ function RenderView(props) {
1349
+ const userPermissions = usePermissions();
1350
+ const handlers = {
1351
+ onClose: () => {
1352
+ props.closePopover();
1353
+ },
1354
+ onGoBack: () => {
1355
+ props.setCurrentView(VIEW_LIST);
1356
+ }
1357
+ };
1358
+ if (userPermissions.canAdd()) {
1359
+ handlers.onAdd = () => {
1360
+ props.setCurrentView(VIEW_ADD);
1361
+ };
1362
+ }
1363
+ if (userPermissions.canEdit()) {
1364
+ handlers.onEdit = (key) => {
1365
+ props.setEditId(key);
1366
+ props.setCurrentView(VIEW_EDIT);
1367
+ };
1368
+ }
1369
+ if (userPermissions.canManageSettings() && props.onSettings) {
1370
+ handlers.onSettings = () => {
1371
+ props.onSettings?.();
1372
+ props.closePopover();
1373
+ };
1374
+ }
1375
+ const handleSubmitOnEdit = () => {
1376
+ if (props?.selectedVariable?.key === props.editId) {
1377
+ handlers.onClose();
1378
+ } else {
1379
+ handlers.onGoBack?.();
853
1380
  }
854
- ), !hasVariables && /* @__PURE__ */ React9.createElement(
855
- NoVariables,
1381
+ };
1382
+ if (VIEW_LIST === props.currentView) {
1383
+ return /* @__PURE__ */ React14.createElement(
1384
+ VariablesSelection,
1385
+ {
1386
+ closePopover: handlers.onClose,
1387
+ onAdd: handlers.onAdd,
1388
+ onEdit: handlers.onEdit,
1389
+ onSettings: handlers.onSettings
1390
+ }
1391
+ );
1392
+ }
1393
+ if (VIEW_ADD === props.currentView) {
1394
+ return /* @__PURE__ */ React14.createElement(VariableCreation, { onGoBack: handlers.onGoBack, onClose: handlers.onClose });
1395
+ }
1396
+ if (VIEW_EDIT === props.currentView) {
1397
+ return /* @__PURE__ */ React14.createElement(
1398
+ VariableEdit,
1399
+ {
1400
+ editId: props.editId,
1401
+ onGoBack: handlers.onGoBack,
1402
+ onClose: handlers.onClose,
1403
+ onSubmit: handleSubmitOnEdit
1404
+ }
1405
+ );
1406
+ }
1407
+ return null;
1408
+ }
1409
+
1410
+ // src/components/ui/tags/assigned-tag.tsx
1411
+ var React15 = __toESM(require("react"));
1412
+ var import_icons8 = require("@elementor/icons");
1413
+ var import_ui15 = require("@elementor/ui");
1414
+ var import_i18n14 = require("@wordpress/i18n");
1415
+ var SIZE5 = "tiny";
1416
+ var AssignedTag = ({ startIcon, label, onUnlink, ...props }) => {
1417
+ const actions = [];
1418
+ if (onUnlink) {
1419
+ actions.push(
1420
+ /* @__PURE__ */ React15.createElement(import_ui15.IconButton, { key: "unlink", size: SIZE5, onClick: onUnlink, "aria-label": (0, import_i18n14.__)("Unlink", "elementor") }, /* @__PURE__ */ React15.createElement(import_icons8.DetachIcon, { fontSize: SIZE5 }))
1421
+ );
1422
+ }
1423
+ return /* @__PURE__ */ React15.createElement(import_ui15.Tooltip, { title: label, placement: "top" }, /* @__PURE__ */ React15.createElement(
1424
+ import_ui15.UnstableTag,
856
1425
  {
857
- title: (0, import_i18n10.__)("Create your first color variable", "elementor"),
858
- icon: /* @__PURE__ */ React9.createElement(import_icons5.BrushIcon, { fontSize: "large" }),
859
- onAdd
1426
+ fullWidth: true,
1427
+ showActionsOnHover: true,
1428
+ startIcon: /* @__PURE__ */ React15.createElement(import_ui15.Stack, { gap: 0.5, direction: "row", alignItems: "center" }, startIcon),
1429
+ label: /* @__PURE__ */ React15.createElement(import_ui15.Box, { sx: { display: "inline-grid", minWidth: 0 } }, /* @__PURE__ */ React15.createElement(import_ui15.Typography, { sx: { lineHeight: 1.34 }, variant: "caption", noWrap: true }, label)),
1430
+ actions,
1431
+ ...props
860
1432
  }
861
- )));
1433
+ ));
862
1434
  };
863
1435
 
864
- // src/components/font-variable-creation.tsx
865
- var React11 = __toESM(require("react"));
866
- var import_react9 = require("react");
867
- var import_editor_controls5 = require("@elementor/editor-controls");
868
- var import_editor_editing_panel5 = require("@elementor/editor-editing-panel");
869
- var import_editor_ui5 = require("@elementor/editor-ui");
870
- var import_icons7 = require("@elementor/icons");
871
- var import_ui13 = require("@elementor/ui");
872
- var import_i18n12 = require("@wordpress/i18n");
873
-
874
- // src/components/fields/font-field.tsx
875
- var React10 = __toESM(require("react"));
876
- var import_react8 = require("react");
877
- var import_editor_controls4 = require("@elementor/editor-controls");
878
- var import_editor_editing_panel4 = require("@elementor/editor-editing-panel");
879
- var import_icons6 = require("@elementor/icons");
880
- var import_ui12 = require("@elementor/ui");
881
- var import_i18n11 = require("@wordpress/i18n");
882
- var FontField = ({ value, onChange }) => {
883
- const [fontFamily, setFontFamily] = (0, import_react8.useState)(value);
884
- const [errorMessage, setErrorMessage] = (0, import_react8.useState)("");
885
- const defaultRef = (0, import_react8.useRef)(null);
886
- const anchorRef = usePopoverContentRef() ?? defaultRef;
887
- const fontPopoverState = (0, import_ui12.usePopupState)({ variant: "popover" });
888
- const fontFamilies = (0, import_editor_editing_panel4.useFontFamilies)();
889
- const sectionWidth = (0, import_editor_editing_panel4.useSectionWidth)();
890
- const handleChange = (newValue) => {
891
- setFontFamily(newValue);
892
- const errorMsg = validateValue(newValue);
893
- setErrorMessage(errorMsg);
894
- onChange(errorMsg ? "" : newValue);
895
- };
896
- const handleFontFamilyChange = (newFontFamily) => {
897
- handleChange(newFontFamily);
898
- fontPopoverState.close();
1436
+ // src/components/ui/variable/assigned-variable.tsx
1437
+ var AssignedVariable = ({ variable, propTypeKey }) => {
1438
+ const { fallbackPropTypeUtil, startIcon, propTypeUtil } = getVariableType(propTypeKey);
1439
+ const { setValue } = (0, import_editor_controls5.useBoundProp)();
1440
+ const anchorRef = (0, import_react11.useRef)(null);
1441
+ const popupId = (0, import_react11.useId)();
1442
+ const popupState = (0, import_ui16.usePopupState)({
1443
+ variant: "popover",
1444
+ popupId: `elementor-variables-list-${popupId}`
1445
+ });
1446
+ const unlinkVariable = () => {
1447
+ const fallbackValue = fallbackPropTypeUtil.create(variable.value);
1448
+ setValue(fallbackValue);
899
1449
  };
900
- return /* @__PURE__ */ React10.createElement(import_ui12.Grid, { container: true, gap: 0.75, alignItems: "center" }, /* @__PURE__ */ React10.createElement(import_ui12.Grid, { item: true, xs: 12 }, /* @__PURE__ */ React10.createElement(import_ui12.FormLabel, { size: "tiny" }, (0, import_i18n11.__)("Value", "elementor"))), /* @__PURE__ */ React10.createElement(import_ui12.Grid, { item: true, xs: 12 }, /* @__PURE__ */ React10.createElement(
901
- import_ui12.UnstableTag,
1450
+ const StartIcon = startIcon || (() => null);
1451
+ return /* @__PURE__ */ React16.createElement(import_ui16.Box, { ref: anchorRef }, /* @__PURE__ */ React16.createElement(
1452
+ AssignedTag,
902
1453
  {
903
- variant: "outlined",
904
- label: fontFamily,
905
- endIcon: /* @__PURE__ */ React10.createElement(import_icons6.ChevronDownIcon, { fontSize: "tiny" }),
906
- ...(0, import_ui12.bindTrigger)(fontPopoverState),
907
- fullWidth: true
1454
+ label: variable.label,
1455
+ startIcon: /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(import_icons9.ColorFilterIcon, { fontSize: SIZE5 }), /* @__PURE__ */ React16.createElement(StartIcon, { value: variable.value })),
1456
+ onUnlink: unlinkVariable,
1457
+ ...(0, import_ui16.bindTrigger)(popupState)
908
1458
  }
909
- ), /* @__PURE__ */ React10.createElement(
910
- import_ui12.Popover,
1459
+ ), /* @__PURE__ */ React16.createElement(
1460
+ import_ui16.Popover,
911
1461
  {
912
- disablePortal: true,
913
1462
  disableScrollLock: true,
914
1463
  anchorEl: anchorRef.current,
915
- anchorOrigin: { vertical: "top", horizontal: "right" },
916
- transformOrigin: { vertical: "top", horizontal: -20 },
917
- ...(0, import_ui12.bindPopover)(fontPopoverState)
1464
+ anchorOrigin: { vertical: "bottom", horizontal: "right" },
1465
+ transformOrigin: { vertical: "top", horizontal: "right" },
1466
+ PaperProps: {
1467
+ sx: { my: 1 }
1468
+ },
1469
+ ...(0, import_ui16.bindPopover)(popupState)
918
1470
  },
919
- /* @__PURE__ */ React10.createElement(
920
- import_editor_controls4.FontFamilySelector,
1471
+ /* @__PURE__ */ React16.createElement(
1472
+ VariableSelectionPopover,
921
1473
  {
922
- fontFamilies,
923
- fontFamily,
924
- onFontFamilyChange: handleFontFamilyChange,
925
- onClose: fontPopoverState.close,
926
- sectionWidth
1474
+ selectedVariable: variable,
1475
+ closePopover: popupState.close,
1476
+ propTypeKey: propTypeUtil.key
927
1477
  }
928
1478
  )
929
- ), errorMessage && /* @__PURE__ */ React10.createElement(import_ui12.FormHelperText, { error: true }, errorMessage)));
1479
+ ));
930
1480
  };
931
1481
 
932
- // src/components/font-variable-creation.tsx
933
- var SIZE5 = "tiny";
934
- var FontVariableCreation = ({ onClose, onGoBack }) => {
935
- const { setValue: setVariable } = (0, import_editor_controls5.useBoundProp)(fontVariablePropTypeUtil);
936
- const [fontFamily, setFontFamily] = (0, import_react9.useState)("");
937
- const [label, setLabel] = (0, import_react9.useState)("");
938
- const resetFields = () => {
939
- setFontFamily("");
940
- setLabel("");
941
- };
942
- const closePopover = () => {
943
- resetFields();
944
- onClose();
945
- };
946
- const handleCreate = () => {
947
- createVariable({
948
- value: fontFamily,
949
- label,
950
- type: fontVariablePropTypeUtil.key
951
- }).then((key) => {
952
- setVariable(key);
953
- closePopover();
954
- });
955
- };
956
- const hasEmptyValue = () => {
957
- return "" === fontFamily.trim() || "" === label.trim();
958
- };
959
- const isSubmitDisabled = hasEmptyValue();
960
- return /* @__PURE__ */ React11.createElement(import_editor_editing_panel5.PopoverScrollableContent, { height: "auto" }, /* @__PURE__ */ React11.createElement(
961
- import_editor_ui5.PopoverHeader,
962
- {
963
- icon: /* @__PURE__ */ React11.createElement(React11.Fragment, null, onGoBack && /* @__PURE__ */ React11.createElement(import_ui13.IconButton, { size: SIZE5, "aria-label": (0, import_i18n12.__)("Go Back", "elementor"), onClick: onGoBack }, /* @__PURE__ */ React11.createElement(import_icons7.ArrowLeftIcon, { fontSize: SIZE5 })), /* @__PURE__ */ React11.createElement(import_icons7.TextIcon, { fontSize: SIZE5 })),
964
- title: (0, import_i18n12.__)("Create variable", "elementor"),
965
- onClose: closePopover
966
- }
967
- ), /* @__PURE__ */ React11.createElement(import_ui13.Divider, null), /* @__PURE__ */ React11.createElement(import_editor_controls5.PopoverContent, { p: 2 }, /* @__PURE__ */ React11.createElement(LabelField, { value: label, onChange: setLabel }), /* @__PURE__ */ React11.createElement(FontField, { value: fontFamily, onChange: setFontFamily })), /* @__PURE__ */ React11.createElement(import_ui13.CardActions, { sx: { pt: 0.5, pb: 1 } }, /* @__PURE__ */ React11.createElement(import_ui13.Button, { size: "small", variant: "contained", disabled: isSubmitDisabled, onClick: handleCreate }, (0, import_i18n12.__)("Create", "elementor"))));
968
- };
1482
+ // src/components/ui/variable/deleted-variable.tsx
1483
+ var React20 = __toESM(require("react"));
1484
+ var import_react13 = require("react");
1485
+ var import_editor_controls7 = require("@elementor/editor-controls");
1486
+ var import_ui20 = require("@elementor/ui");
969
1487
 
970
- // src/components/font-variable-edit.tsx
971
- var React12 = __toESM(require("react"));
972
- var import_react10 = require("react");
1488
+ // src/components/variable-restore.tsx
1489
+ var React17 = __toESM(require("react"));
1490
+ var import_react12 = require("react");
973
1491
  var import_editor_controls6 = require("@elementor/editor-controls");
974
- var import_editor_editing_panel6 = require("@elementor/editor-editing-panel");
1492
+ var import_editor_editing_panel5 = require("@elementor/editor-editing-panel");
975
1493
  var import_editor_ui6 = require("@elementor/editor-ui");
976
- var import_icons8 = require("@elementor/icons");
977
- var import_ui14 = require("@elementor/ui");
978
- var import_i18n13 = require("@wordpress/i18n");
1494
+ var import_ui17 = require("@elementor/ui");
1495
+ var import_i18n15 = require("@wordpress/i18n");
979
1496
  var SIZE6 = "tiny";
980
- var FontVariableEdit = ({ onClose, onGoBack, onSubmit, editId }) => {
981
- const { setValue: notifyBoundPropChange, value: assignedValue } = (0, import_editor_controls6.useBoundProp)(fontVariablePropTypeUtil);
982
- const [deleteConfirmation, setDeleteConfirmation] = (0, import_react10.useState)(false);
983
- const variable = useVariable(editId);
1497
+ var VariableRestore = ({ variableId, onClose, onSubmit }) => {
1498
+ const { icon: VariableIcon, valueField: ValueField, variableType, propTypeUtil } = useVariableType();
1499
+ const { setValue: notifyBoundPropChange } = (0, import_editor_controls6.useBoundProp)(propTypeUtil);
1500
+ const variable = useVariable(variableId);
984
1501
  if (!variable) {
985
- throw new Error(`Global font variable "${editId}" not found`);
1502
+ throw new Error(`Global ${variableType} variable not found`);
986
1503
  }
987
- const [fontFamily, setFontFamily] = (0, import_react10.useState)(variable.value);
988
- const [label, setLabel] = (0, import_react10.useState)(variable.label);
989
- const handleUpdate = () => {
990
- updateVariable(editId, {
991
- value: fontFamily,
992
- label
993
- }).then(() => {
994
- maybeTriggerBoundPropChange();
995
- onSubmit?.();
996
- });
997
- };
998
- const handleDelete = () => {
999
- deleteVariable(editId).then(() => {
1000
- maybeTriggerBoundPropChange();
1504
+ const [errorMessage, setErrorMessage] = (0, import_react12.useState)("");
1505
+ const [label, setLabel] = (0, import_react12.useState)(variable.label);
1506
+ const [value, setValue] = (0, import_react12.useState)(variable.value);
1507
+ const { labelFieldError, setLabelFieldError } = useLabelError({
1508
+ value: variable.label,
1509
+ message: ERROR_MESSAGES.DUPLICATED_LABEL
1510
+ });
1511
+ const handleRestore = () => {
1512
+ restoreVariable(variableId, label, value).then(() => {
1513
+ notifyBoundPropChange(variableId);
1001
1514
  onSubmit?.();
1515
+ }).catch((error) => {
1516
+ const mappedError = mapServerError(error);
1517
+ if (mappedError && "label" === mappedError.field) {
1518
+ setLabel("");
1519
+ setLabelFieldError({
1520
+ value: label,
1521
+ message: mappedError.message
1522
+ });
1523
+ return;
1524
+ }
1525
+ setErrorMessage(ERROR_MESSAGES.UNEXPECTED_ERROR);
1002
1526
  });
1003
1527
  };
1004
- const maybeTriggerBoundPropChange = () => {
1005
- if (editId === assignedValue) {
1006
- notifyBoundPropChange(editId);
1007
- }
1008
- };
1009
- const handleDeleteConfirmation = () => {
1010
- setDeleteConfirmation(true);
1011
- };
1012
- const closeDeleteDialog = () => () => {
1013
- setDeleteConfirmation(false);
1014
- };
1015
- const hasEmptyValue = () => {
1016
- return !fontFamily.trim() || !label.trim();
1528
+ const hasEmptyValues = () => {
1529
+ return !value.trim() || !label.trim();
1017
1530
  };
1018
1531
  const noValueChanged = () => {
1019
- return fontFamily === variable.value && label === variable.label;
1532
+ return value === variable.value && label === variable.label;
1020
1533
  };
1021
- const isSubmitDisabled = noValueChanged() || hasEmptyValue();
1022
- const actions = [];
1023
- actions.push(
1024
- /* @__PURE__ */ React12.createElement(
1025
- import_ui14.IconButton,
1026
- {
1027
- key: "delete",
1028
- size: SIZE6,
1029
- "aria-label": (0, import_i18n13.__)("Delete", "elementor"),
1030
- onClick: handleDeleteConfirmation
1031
- },
1032
- /* @__PURE__ */ React12.createElement(import_icons8.TrashIcon, { fontSize: SIZE6 })
1033
- )
1034
- );
1035
- return /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(import_editor_editing_panel6.PopoverScrollableContent, { height: "auto" }, /* @__PURE__ */ React12.createElement(
1036
- import_editor_ui6.PopoverHeader,
1037
- {
1038
- icon: /* @__PURE__ */ React12.createElement(React12.Fragment, null, onGoBack && /* @__PURE__ */ React12.createElement(
1039
- import_ui14.IconButton,
1040
- {
1041
- size: SIZE6,
1042
- "aria-label": (0, import_i18n13.__)("Go Back", "elementor"),
1043
- onClick: onGoBack
1044
- },
1045
- /* @__PURE__ */ React12.createElement(import_icons8.ArrowLeftIcon, { fontSize: SIZE6 })
1046
- ), /* @__PURE__ */ React12.createElement(import_icons8.TextIcon, { fontSize: SIZE6 })),
1047
- title: (0, import_i18n13.__)("Edit variable", "elementor"),
1048
- onClose,
1049
- actions
1050
- }
1051
- ), /* @__PURE__ */ React12.createElement(import_ui14.Divider, null), /* @__PURE__ */ React12.createElement(import_editor_controls6.PopoverContent, { p: 2 }, /* @__PURE__ */ React12.createElement(LabelField, { value: label, onChange: setLabel }), /* @__PURE__ */ React12.createElement(FontField, { value: fontFamily, onChange: setFontFamily })), /* @__PURE__ */ React12.createElement(import_ui14.CardActions, { sx: { pt: 0.5, pb: 1 } }, /* @__PURE__ */ React12.createElement(import_ui14.Button, { size: "small", variant: "contained", disabled: isSubmitDisabled, onClick: handleUpdate }, (0, import_i18n13.__)("Save", "elementor")))), deleteConfirmation && /* @__PURE__ */ React12.createElement(
1052
- DeleteConfirmationDialog,
1053
- {
1054
- open: true,
1055
- label,
1056
- onConfirm: handleDelete,
1057
- closeDialog: closeDeleteDialog()
1058
- }
1059
- ));
1060
- };
1061
-
1062
- // src/components/font-variables-selection.tsx
1063
- var React13 = __toESM(require("react"));
1064
- var import_react11 = require("react");
1065
- var import_editor_controls7 = require("@elementor/editor-controls");
1066
- var import_editor_editing_panel7 = require("@elementor/editor-editing-panel");
1067
- var import_editor_ui7 = require("@elementor/editor-ui");
1068
- var import_icons9 = require("@elementor/icons");
1069
- var import_ui15 = require("@elementor/ui");
1070
- var import_i18n14 = require("@wordpress/i18n");
1071
- var SIZE7 = "tiny";
1072
- var FontVariablesSelection = ({ closePopover, onAdd, onEdit, onSettings }) => {
1073
- const { value: variable, setValue: setVariable } = (0, import_editor_controls7.useBoundProp)(fontVariablePropTypeUtil);
1074
- const [searchValue, setSearchValue] = (0, import_react11.useState)("");
1075
- const {
1076
- list: variables,
1077
- hasMatches: hasSearchResults,
1078
- isSourceNotEmpty: hasVariables
1079
- } = useFilteredVariables(searchValue, fontVariablePropTypeUtil.key);
1080
- const handleSetVariable = (key) => {
1081
- setVariable(key);
1082
- closePopover();
1534
+ const hasErrors = () => {
1535
+ return !!errorMessage;
1083
1536
  };
1084
- const actions = [];
1085
- if (onAdd) {
1086
- actions.push(
1087
- /* @__PURE__ */ React13.createElement(import_ui15.IconButton, { key: "add", size: SIZE7, onClick: onAdd }, /* @__PURE__ */ React13.createElement(import_icons9.PlusIcon, { fontSize: SIZE7 }))
1088
- );
1089
- }
1090
- if (onSettings) {
1091
- actions.push(
1092
- /* @__PURE__ */ React13.createElement(import_ui15.IconButton, { key: "settings", size: SIZE7, onClick: onSettings }, /* @__PURE__ */ React13.createElement(import_icons9.SettingsIcon, { fontSize: SIZE7 }))
1093
- );
1094
- }
1095
- const items = variables.map(({ value, label, key }) => ({
1096
- type: "item",
1097
- value: key,
1098
- label,
1099
- icon: /* @__PURE__ */ React13.createElement(import_icons9.TextIcon, { fontSize: SIZE7 }),
1100
- secondaryText: value,
1101
- onEdit: () => onEdit?.(key)
1102
- }));
1103
- const handleSearch = (search) => {
1104
- setSearchValue(search);
1105
- };
1106
- const handleClearSearch = () => {
1107
- setSearchValue("");
1108
- };
1109
- return /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(
1110
- import_editor_ui7.PopoverHeader,
1111
- {
1112
- title: (0, import_i18n14.__)("Variables", "elementor"),
1113
- onClose: closePopover,
1114
- icon: /* @__PURE__ */ React13.createElement(import_icons9.ColorFilterIcon, { fontSize: SIZE7 }),
1115
- actions
1116
- }
1117
- ), hasVariables && /* @__PURE__ */ React13.createElement(
1118
- import_editor_ui7.PopoverSearch,
1537
+ const isSubmitDisabled = noValueChanged() || hasEmptyValues() || hasErrors();
1538
+ return /* @__PURE__ */ React17.createElement(PopoverContentRefContextProvider, null, /* @__PURE__ */ React17.createElement(import_editor_editing_panel5.PopoverBody, { height: "auto" }, /* @__PURE__ */ React17.createElement(
1539
+ import_editor_ui6.PopoverHeader,
1119
1540
  {
1120
- value: searchValue,
1121
- onSearch: handleSearch,
1122
- placeholder: (0, import_i18n14.__)("Search", "elementor")
1541
+ icon: /* @__PURE__ */ React17.createElement(VariableIcon, { fontSize: SIZE6 }),
1542
+ title: (0, import_i18n15.__)("Restore variable", "elementor"),
1543
+ onClose
1123
1544
  }
1124
- ), /* @__PURE__ */ React13.createElement(import_ui15.Divider, null), /* @__PURE__ */ React13.createElement(import_editor_editing_panel7.PopoverScrollableContent, null, hasVariables && hasSearchResults && /* @__PURE__ */ React13.createElement(
1125
- import_editor_ui7.PopoverMenuList,
1126
- {
1127
- items,
1128
- onSelect: handleSetVariable,
1129
- onClose: () => {
1130
- },
1131
- selectedValue: variable,
1132
- "data-testid": "font-variables-list",
1133
- menuListTemplate: VariablesStyledMenuList,
1134
- menuItemContentTemplate: (item) => /* @__PURE__ */ React13.createElement(MenuItemContent, { item })
1135
- }
1136
- ), !hasSearchResults && hasVariables && /* @__PURE__ */ React13.createElement(
1137
- NoSearchResults,
1545
+ ), /* @__PURE__ */ React17.createElement(import_ui17.Divider, null), /* @__PURE__ */ React17.createElement(import_editor_controls6.PopoverContent, { p: 2 }, /* @__PURE__ */ React17.createElement(
1546
+ LabelField,
1138
1547
  {
1139
- searchValue,
1140
- onClear: handleClearSearch,
1141
- icon: /* @__PURE__ */ React13.createElement(import_icons9.TextIcon, { fontSize: "large" })
1548
+ value: label,
1549
+ error: labelFieldError,
1550
+ onChange: (newValue) => {
1551
+ setLabel(newValue);
1552
+ setErrorMessage("");
1553
+ }
1142
1554
  }
1143
- ), !hasVariables && /* @__PURE__ */ React13.createElement(
1144
- NoVariables,
1555
+ ), /* @__PURE__ */ React17.createElement(
1556
+ ValueField,
1145
1557
  {
1146
- title: (0, import_i18n14.__)("Create your first font variable", "elementor"),
1147
- icon: /* @__PURE__ */ React13.createElement(import_icons9.TextIcon, { fontSize: "large" }),
1148
- onAdd
1558
+ value,
1559
+ onChange: (newValue) => {
1560
+ setValue(newValue);
1561
+ setErrorMessage("");
1562
+ }
1149
1563
  }
1150
- )));
1564
+ ), errorMessage && /* @__PURE__ */ React17.createElement(import_ui17.FormHelperText, { error: true }, errorMessage)), /* @__PURE__ */ React17.createElement(import_ui17.CardActions, { sx: { pt: 0.5, pb: 1 } }, /* @__PURE__ */ React17.createElement(import_ui17.Button, { size: "small", variant: "contained", disabled: isSubmitDisabled, onClick: handleRestore }, (0, import_i18n15.__)("Restore", "elementor")))));
1151
1565
  };
1152
1566
 
1153
- // src/components/variable-selection-popover.tsx
1154
- var VIEW_LIST = "list";
1155
- var VIEW_ADD = "add";
1156
- var VIEW_EDIT = "edit";
1157
- var VariableSelectionPopover = ({ closePopover, propTypeKey, selectedVariable }) => {
1158
- const [currentView, setCurrentView] = (0, import_react12.useState)(VIEW_LIST);
1159
- const editIdRef = (0, import_react12.useRef)("");
1160
- const anchorRef = (0, import_react12.useRef)(null);
1161
- return /* @__PURE__ */ React14.createElement(PopoverContentRefContext.Provider, { value: anchorRef }, /* @__PURE__ */ React14.createElement(import_ui16.Box, { ref: anchorRef }, renderStage({
1162
- propTypeKey,
1163
- currentView,
1164
- selectedVariable,
1165
- editIdRef,
1166
- setCurrentView,
1167
- closePopover
1168
- })));
1567
+ // src/components/ui/deleted-variable-alert.tsx
1568
+ var React18 = __toESM(require("react"));
1569
+ var import_editor_editing_panel6 = require("@elementor/editor-editing-panel");
1570
+ var import_ui18 = require("@elementor/ui");
1571
+ var import_i18n16 = require("@wordpress/i18n");
1572
+ var DeletedVariableAlert = ({ onClose, onUnlink, onRestore, label }) => {
1573
+ const sectionWidth = (0, import_editor_editing_panel6.useSectionWidth)();
1574
+ return /* @__PURE__ */ React18.createElement(import_ui18.ClickAwayListener, { onClickAway: onClose }, /* @__PURE__ */ React18.createElement(
1575
+ import_ui18.Alert,
1576
+ {
1577
+ variant: "standard",
1578
+ severity: "warning",
1579
+ onClose,
1580
+ action: /* @__PURE__ */ React18.createElement(React18.Fragment, null, onUnlink && /* @__PURE__ */ React18.createElement(import_ui18.AlertAction, { variant: "contained", onClick: onUnlink }, (0, import_i18n16.__)("Unlink", "elementor")), onRestore && /* @__PURE__ */ React18.createElement(import_ui18.AlertAction, { variant: "outlined", onClick: onRestore }, (0, import_i18n16.__)("Restore", "elementor"))),
1581
+ sx: { width: sectionWidth }
1582
+ },
1583
+ /* @__PURE__ */ React18.createElement(import_ui18.AlertTitle, null, (0, import_i18n16.__)("Deleted variable", "elementor")),
1584
+ (0, import_i18n16.__)("The variable", "elementor"),
1585
+ " '",
1586
+ label,
1587
+ "'",
1588
+ " ",
1589
+ (0, import_i18n16.__)(
1590
+ "has been deleted, but it is still referenced in this location. You may restore the variable or unlink it to assign a different value.",
1591
+ "elementor"
1592
+ )
1593
+ ));
1169
1594
  };
1170
- function renderStage(props) {
1171
- const handleSubmitOnEdit = () => {
1172
- if (props?.selectedVariable?.key === props.editIdRef.current) {
1173
- props.closePopover();
1174
- } else {
1175
- props.setCurrentView(VIEW_LIST);
1176
- }
1177
- };
1178
- if (fontVariablePropTypeUtil.key === props.propTypeKey) {
1179
- if (VIEW_LIST === props.currentView) {
1180
- return /* @__PURE__ */ React14.createElement(
1181
- FontVariablesSelection,
1182
- {
1183
- closePopover: props.closePopover,
1184
- onAdd: () => {
1185
- props.setCurrentView(VIEW_ADD);
1186
- },
1187
- onEdit: (key) => {
1188
- props.editIdRef.current = key;
1189
- props.setCurrentView(VIEW_EDIT);
1190
- }
1191
- }
1192
- );
1193
- }
1194
- if (VIEW_ADD === props.currentView) {
1195
- return /* @__PURE__ */ React14.createElement(
1196
- FontVariableCreation,
1197
- {
1198
- onGoBack: () => props.setCurrentView(VIEW_LIST),
1199
- onClose: props.closePopover
1200
- }
1201
- );
1202
- }
1203
- if (VIEW_EDIT === props.currentView) {
1204
- return /* @__PURE__ */ React14.createElement(
1205
- FontVariableEdit,
1206
- {
1207
- editId: props.editIdRef.current ?? "",
1208
- onGoBack: () => props.setCurrentView(VIEW_LIST),
1209
- onClose: props.closePopover,
1210
- onSubmit: handleSubmitOnEdit
1211
- }
1212
- );
1213
- }
1214
- }
1215
- if (colorVariablePropTypeUtil.key === props.propTypeKey) {
1216
- if (VIEW_LIST === props.currentView) {
1217
- return /* @__PURE__ */ React14.createElement(
1218
- ColorVariablesSelection,
1219
- {
1220
- closePopover: props.closePopover,
1221
- onAdd: () => {
1222
- props.setCurrentView(VIEW_ADD);
1223
- },
1224
- onEdit: (key) => {
1225
- props.editIdRef.current = key;
1226
- props.setCurrentView(VIEW_EDIT);
1227
- }
1228
- }
1229
- );
1230
- }
1231
- if (VIEW_ADD === props.currentView) {
1232
- return /* @__PURE__ */ React14.createElement(
1233
- ColorVariableCreation,
1234
- {
1235
- onGoBack: () => props.setCurrentView(VIEW_LIST),
1236
- onClose: props.closePopover
1237
- }
1238
- );
1239
- }
1240
- if (VIEW_EDIT === props.currentView) {
1241
- return /* @__PURE__ */ React14.createElement(
1242
- ColorVariableEdit,
1243
- {
1244
- editId: props.editIdRef.current ?? "",
1245
- onGoBack: () => props.setCurrentView(VIEW_LIST),
1246
- onClose: props.closePopover,
1247
- onSubmit: handleSubmitOnEdit
1248
- }
1249
- );
1250
- }
1251
- }
1252
- return null;
1253
- }
1254
1595
 
1255
- // src/components/ui/tags/assigned-tag.tsx
1256
- var React15 = __toESM(require("react"));
1596
+ // src/components/ui/tags/deleted-tag.tsx
1597
+ var React19 = __toESM(require("react"));
1257
1598
  var import_icons10 = require("@elementor/icons");
1258
- var import_ui17 = require("@elementor/ui");
1259
- var import_i18n15 = require("@wordpress/i18n");
1260
- var SIZE8 = "tiny";
1261
- var AssignedTag = ({ startIcon, label, onUnlink, ...props }) => {
1262
- const actions = [];
1263
- if (onUnlink) {
1264
- actions.push(
1265
- /* @__PURE__ */ React15.createElement(import_ui17.IconButton, { key: "unlink", size: SIZE8, onClick: onUnlink, "aria-label": (0, import_i18n15.__)("Unlink", "elementor") }, /* @__PURE__ */ React15.createElement(import_icons10.DetachIcon, { fontSize: SIZE8 }))
1266
- );
1267
- }
1268
- return /* @__PURE__ */ React15.createElement(
1269
- import_ui17.UnstableTag,
1599
+ var import_ui19 = require("@elementor/ui");
1600
+ var import_i18n17 = require("@wordpress/i18n");
1601
+ var DeletedTag = React19.forwardRef(({ label, onClick, ...props }, ref) => {
1602
+ return /* @__PURE__ */ React19.createElement(
1603
+ import_ui19.Chip,
1270
1604
  {
1271
- fullWidth: true,
1272
- showActionsOnHover: true,
1273
- startIcon: /* @__PURE__ */ React15.createElement(import_ui17.Stack, { gap: 0.5, direction: "row", alignItems: "center" }, startIcon),
1274
- label: /* @__PURE__ */ React15.createElement(import_ui17.Box, { sx: { display: "inline-grid", minWidth: 0 } }, /* @__PURE__ */ React15.createElement(import_ui17.Typography, { sx: { lineHeight: 1.34 }, variant: "caption", noWrap: true }, label)),
1275
- actions,
1605
+ ref,
1606
+ size: "tiny",
1607
+ color: "warning",
1608
+ shape: "rounded",
1609
+ variant: "standard",
1610
+ onClick,
1611
+ icon: /* @__PURE__ */ React19.createElement(import_icons10.AlertTriangleFilledIcon, null),
1612
+ label: /* @__PURE__ */ React19.createElement(import_ui19.Tooltip, { title: label, placement: "top" }, /* @__PURE__ */ React19.createElement(import_ui19.Box, { sx: { display: "flex", gap: 0.5, alignItems: "center" } }, /* @__PURE__ */ React19.createElement(import_ui19.Typography, { variant: "caption", noWrap: true }, label), /* @__PURE__ */ React19.createElement(import_ui19.Typography, { variant: "caption", noWrap: true, sx: { textOverflow: "initial", overflow: "visible" } }, "(", (0, import_i18n17.__)("deleted", "elementor"), ")"))),
1613
+ sx: {
1614
+ height: (theme) => theme.spacing(3.5),
1615
+ borderRadius: (theme) => theme.spacing(1),
1616
+ justifyContent: "flex-start",
1617
+ width: "100%"
1618
+ },
1276
1619
  ...props
1277
1620
  }
1278
1621
  );
1279
- };
1622
+ });
1280
1623
 
1281
- // src/components/ui/variable/assigned-variable.tsx
1282
- var AssignedVariable = ({
1283
- variable,
1284
- variablePropTypeUtil,
1285
- fallbackPropTypeUtil,
1286
- additionalStartIcon
1287
- }) => {
1288
- const { setValue } = (0, import_editor_controls8.useBoundProp)();
1289
- const anchorRef = (0, import_react13.useRef)(null);
1624
+ // src/components/ui/variable/deleted-variable.tsx
1625
+ var DeletedVariable = ({ variable, propTypeKey }) => {
1626
+ const { fallbackPropTypeUtil, propTypeUtil } = getVariableType(propTypeKey);
1627
+ const { setValue } = (0, import_editor_controls7.useBoundProp)();
1628
+ const userPermissions = usePermissions();
1629
+ const [showInfotip, setShowInfotip] = (0, import_react13.useState)(false);
1630
+ const toggleInfotip = () => setShowInfotip((prev) => !prev);
1631
+ const closeInfotip = () => setShowInfotip(false);
1632
+ const deletedChipAnchorRef = (0, import_react13.useRef)(null);
1290
1633
  const popupId = (0, import_react13.useId)();
1291
- const popupState = (0, import_ui18.usePopupState)({
1634
+ const popupState = (0, import_ui20.usePopupState)({
1292
1635
  variant: "popover",
1293
- popupId: `elementor-variables-list-${popupId}`
1636
+ popupId: `elementor-variables-restore-${popupId}`
1294
1637
  });
1295
- const unlinkVariable = () => {
1296
- setValue(fallbackPropTypeUtil.create(variable.value));
1638
+ const handlers = {};
1639
+ if (userPermissions.canUnlink()) {
1640
+ handlers.onUnlink = () => {
1641
+ setValue(fallbackPropTypeUtil.create(variable.value));
1642
+ };
1643
+ }
1644
+ if (userPermissions.canRestore()) {
1645
+ handlers.onRestore = () => {
1646
+ if (!variable.key) {
1647
+ return;
1648
+ }
1649
+ restoreVariable(variable.key).then((key) => {
1650
+ setValue(propTypeUtil.create(key));
1651
+ closeInfotip();
1652
+ }).catch(() => {
1653
+ closeInfotip();
1654
+ popupState.setAnchorEl(deletedChipAnchorRef.current);
1655
+ popupState.open();
1656
+ });
1657
+ };
1658
+ }
1659
+ const handleRestoreWithOverrides = () => {
1660
+ popupState.close();
1297
1661
  };
1298
- return /* @__PURE__ */ React16.createElement(import_ui18.Box, { ref: anchorRef }, /* @__PURE__ */ React16.createElement(
1299
- AssignedTag,
1662
+ return /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement(import_ui20.Box, { ref: deletedChipAnchorRef }, showInfotip && /* @__PURE__ */ React20.createElement(import_ui20.Backdrop, { open: true, onClick: closeInfotip, invisible: true }), /* @__PURE__ */ React20.createElement(
1663
+ import_ui20.Infotip,
1300
1664
  {
1301
- label: variable.label,
1302
- startIcon: /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(import_icons11.ColorFilterIcon, { fontSize: SIZE8 }), additionalStartIcon),
1303
- onUnlink: unlinkVariable,
1304
- ...(0, import_ui18.bindTrigger)(popupState)
1305
- }
1306
- ), /* @__PURE__ */ React16.createElement(
1307
- import_ui18.Popover,
1665
+ color: "warning",
1666
+ placement: "right-start",
1667
+ open: showInfotip,
1668
+ disableHoverListener: true,
1669
+ onClose: closeInfotip,
1670
+ content: /* @__PURE__ */ React20.createElement(
1671
+ DeletedVariableAlert,
1672
+ {
1673
+ onClose: closeInfotip,
1674
+ onUnlink: handlers.onUnlink,
1675
+ onRestore: handlers.onRestore,
1676
+ label: variable.label
1677
+ }
1678
+ ),
1679
+ slotProps: {
1680
+ popper: {
1681
+ modifiers: [
1682
+ {
1683
+ name: "offset",
1684
+ options: { offset: [0, 24] }
1685
+ }
1686
+ ]
1687
+ }
1688
+ }
1689
+ },
1690
+ /* @__PURE__ */ React20.createElement(DeletedTag, { label: variable.label, onClick: toggleInfotip })
1691
+ ), /* @__PURE__ */ React20.createElement(
1692
+ import_ui20.Popover,
1308
1693
  {
1309
1694
  disableScrollLock: true,
1310
- anchorEl: anchorRef.current,
1311
1695
  anchorOrigin: { vertical: "bottom", horizontal: "right" },
1312
1696
  transformOrigin: { vertical: "top", horizontal: "right" },
1313
1697
  PaperProps: {
1314
1698
  sx: { my: 1 }
1315
1699
  },
1316
- ...(0, import_ui18.bindPopover)(popupState)
1700
+ ...(0, import_ui20.bindPopover)(popupState)
1317
1701
  },
1318
- /* @__PURE__ */ React16.createElement(
1319
- VariableSelectionPopover,
1702
+ /* @__PURE__ */ React20.createElement(VariableTypeProvider, { propTypeKey }, /* @__PURE__ */ React20.createElement(
1703
+ VariableRestore,
1320
1704
  {
1321
- selectedVariable: variable,
1322
- closePopover: popupState.close,
1323
- propTypeKey: variablePropTypeUtil.key
1705
+ variableId: variable.key ?? "",
1706
+ onClose: popupState.close,
1707
+ onSubmit: handleRestoreWithOverrides
1324
1708
  }
1325
- )
1326
- ));
1709
+ ))
1710
+ )));
1327
1711
  };
1328
1712
 
1329
- // src/components/ui/variable/deleted-variable.tsx
1330
- var React18 = __toESM(require("react"));
1713
+ // src/components/ui/variable/missing-variable.tsx
1714
+ var React23 = __toESM(require("react"));
1331
1715
  var import_react14 = require("react");
1332
- var import_ui20 = require("@elementor/ui");
1716
+ var import_editor_controls8 = require("@elementor/editor-controls");
1717
+ var import_ui23 = require("@elementor/ui");
1718
+ var import_i18n19 = require("@wordpress/i18n");
1333
1719
 
1334
- // src/components/ui/tags/deleted-tag.tsx
1335
- var React17 = __toESM(require("react"));
1336
- var import_icons12 = require("@elementor/icons");
1337
- var import_ui19 = require("@elementor/ui");
1338
- var import_i18n16 = require("@wordpress/i18n");
1339
- var DeletedTag = ({ label }) => {
1340
- return /* @__PURE__ */ React17.createElement(
1341
- import_ui19.UnstableTag,
1720
+ // src/components/ui/missing-variable-alert.tsx
1721
+ var React21 = __toESM(require("react"));
1722
+ var import_editor_editing_panel7 = require("@elementor/editor-editing-panel");
1723
+ var import_ui21 = require("@elementor/ui");
1724
+ var import_i18n18 = require("@wordpress/i18n");
1725
+ var MissingVariableAlert = ({ onClose, onClear }) => {
1726
+ const sectionWidth = (0, import_editor_editing_panel7.useSectionWidth)();
1727
+ return /* @__PURE__ */ React21.createElement(import_ui21.ClickAwayListener, { onClickAway: onClose }, /* @__PURE__ */ React21.createElement(
1728
+ import_ui21.Alert,
1342
1729
  {
1343
- showActionsOnHover: true,
1344
- fullWidth: true,
1345
- label: /* @__PURE__ */ React17.createElement(import_ui19.Box, { sx: { display: "inline-grid", minWidth: 0 } }, /* @__PURE__ */ React17.createElement(import_ui19.Typography, { sx: { lineHeight: 1.34 }, variant: "caption", noWrap: true }, label)),
1346
- startIcon: /* @__PURE__ */ React17.createElement(import_icons12.ColorFilterIcon, { fontSize: "tiny" }),
1347
- endAdornment: /* @__PURE__ */ React17.createElement(import_ui19.Typography, { sx: { lineHeight: 1.34 }, variant: "caption", noWrap: true }, "(", (0, import_i18n16.__)("deleted", "elementor"), ")")
1730
+ variant: "standard",
1731
+ severity: "warning",
1732
+ onClose,
1733
+ action: /* @__PURE__ */ React21.createElement(React21.Fragment, null, onClear && /* @__PURE__ */ React21.createElement(import_ui21.AlertAction, { variant: "contained", onClick: onClear }, (0, import_i18n18.__)("Clear", "elementor"))),
1734
+ sx: { width: sectionWidth }
1735
+ },
1736
+ /* @__PURE__ */ React21.createElement(import_ui21.AlertTitle, null, (0, import_i18n18.__)("This variable is missing", "elementor")),
1737
+ (0, import_i18n18.__)(
1738
+ "It may have been deleted. Try clearing this field and select a different value or variable.",
1739
+ "elementor"
1740
+ )
1741
+ ));
1742
+ };
1743
+
1744
+ // src/components/ui/tags/missing-tag.tsx
1745
+ var React22 = __toESM(require("react"));
1746
+ var import_icons11 = require("@elementor/icons");
1747
+ var import_ui22 = require("@elementor/ui");
1748
+ var MissingTag = React22.forwardRef(({ label, onClick, ...props }, ref) => {
1749
+ return /* @__PURE__ */ React22.createElement(
1750
+ import_ui22.Chip,
1751
+ {
1752
+ ref,
1753
+ size: "tiny",
1754
+ color: "warning",
1755
+ shape: "rounded",
1756
+ variant: "standard",
1757
+ onClick,
1758
+ icon: /* @__PURE__ */ React22.createElement(import_icons11.AlertTriangleFilledIcon, null),
1759
+ label,
1760
+ sx: {
1761
+ height: (theme) => theme.spacing(3.5),
1762
+ borderRadius: (theme) => theme.spacing(1),
1763
+ justifyContent: "flex-start",
1764
+ width: "100%"
1765
+ },
1766
+ ...props
1348
1767
  }
1349
1768
  );
1350
- };
1769
+ });
1351
1770
 
1352
- // src/components/ui/variable/deleted-variable.tsx
1353
- var DeletedVariable = ({ variable }) => {
1354
- const anchorRef = (0, import_react14.useRef)(null);
1355
- return /* @__PURE__ */ React18.createElement(import_ui20.Box, { ref: anchorRef }, /* @__PURE__ */ React18.createElement(DeletedTag, { label: variable.label }));
1771
+ // src/components/ui/variable/missing-variable.tsx
1772
+ var MissingVariable = () => {
1773
+ const { setValue } = (0, import_editor_controls8.useBoundProp)();
1774
+ const [infotipVisible, setInfotipVisible] = (0, import_react14.useState)(false);
1775
+ const toggleInfotip = () => setInfotipVisible((prev) => !prev);
1776
+ const closeInfotip = () => setInfotipVisible(false);
1777
+ const clearValue = () => setValue(null);
1778
+ return /* @__PURE__ */ React23.createElement(React23.Fragment, null, infotipVisible && /* @__PURE__ */ React23.createElement(import_ui23.Backdrop, { open: true, onClick: closeInfotip, invisible: true }), /* @__PURE__ */ React23.createElement(
1779
+ import_ui23.Infotip,
1780
+ {
1781
+ color: "warning",
1782
+ placement: "right-start",
1783
+ open: infotipVisible,
1784
+ disableHoverListener: true,
1785
+ onClose: closeInfotip,
1786
+ content: /* @__PURE__ */ React23.createElement(MissingVariableAlert, { onClose: closeInfotip, onClear: clearValue }),
1787
+ slotProps: {
1788
+ popper: {
1789
+ modifiers: [
1790
+ {
1791
+ name: "offset",
1792
+ options: { offset: [0, 24] }
1793
+ }
1794
+ ]
1795
+ }
1796
+ }
1797
+ },
1798
+ /* @__PURE__ */ React23.createElement(MissingTag, { label: (0, import_i18n19.__)("Missing variable", "elementor"), onClick: toggleInfotip })
1799
+ ));
1356
1800
  };
1357
1801
 
1358
- // src/controls/color-variable-control.tsx
1359
- var ColorVariableControl = () => {
1360
- const { value: variableValue } = (0, import_editor_controls9.useBoundProp)(colorVariablePropTypeUtil);
1361
- const assignedVariable = useVariable(variableValue);
1802
+ // src/controls/variable-control.tsx
1803
+ var VariableControl = () => {
1804
+ const boundProp = (0, import_editor_controls9.useBoundProp)().value;
1805
+ const assignedVariable = useVariable(boundProp?.value);
1362
1806
  if (!assignedVariable) {
1363
- throw new Error(`Global color variable ${variableValue} not found`);
1807
+ return /* @__PURE__ */ React24.createElement(MissingVariable, null);
1364
1808
  }
1365
- const isVariableDeleted = assignedVariable?.deleted;
1366
- if (isVariableDeleted) {
1367
- return /* @__PURE__ */ React19.createElement(DeletedVariable, { variable: assignedVariable });
1809
+ const { $$type: propTypeKey } = boundProp;
1810
+ if (assignedVariable?.deleted) {
1811
+ return /* @__PURE__ */ React24.createElement(DeletedVariable, { variable: assignedVariable, propTypeKey });
1368
1812
  }
1369
- return /* @__PURE__ */ React19.createElement(
1370
- AssignedVariable,
1371
- {
1372
- variable: assignedVariable,
1373
- variablePropTypeUtil: colorVariablePropTypeUtil,
1374
- fallbackPropTypeUtil: import_editor_props3.colorPropTypeUtil,
1375
- additionalStartIcon: /* @__PURE__ */ React19.createElement(ColorIndicator, { size: "inherit", value: assignedVariable.value, component: "span" })
1376
- }
1377
- );
1813
+ return /* @__PURE__ */ React24.createElement(AssignedVariable, { variable: assignedVariable, propTypeKey });
1378
1814
  };
1379
1815
 
1380
- // src/hooks/use-prop-color-variable-action.tsx
1381
- var React20 = __toESM(require("react"));
1816
+ // src/hooks/use-prop-variable-action.tsx
1817
+ var React25 = __toESM(require("react"));
1382
1818
  var import_editor_editing_panel8 = require("@elementor/editor-editing-panel");
1383
- var import_icons13 = require("@elementor/icons");
1384
- var import_i18n17 = require("@wordpress/i18n");
1385
-
1386
- // src/utils.ts
1387
- var hasAssignedColorVariable = (propValue) => {
1388
- return !!colorVariablePropTypeUtil.isValid(propValue);
1389
- };
1390
- var supportsColorVariables = (propType) => {
1391
- return propType.kind === "union" && colorVariablePropTypeUtil.key in propType.prop_types;
1392
- };
1393
- var hasAssignedFontVariable = (propValue) => {
1394
- return !!fontVariablePropTypeUtil.isValid(propValue);
1395
- };
1396
- var supportsFontVariables = (propType) => {
1397
- return propType.kind === "union" && fontVariablePropTypeUtil.key in propType.prop_types;
1398
- };
1399
-
1400
- // src/hooks/use-prop-color-variable-action.tsx
1401
- var usePropColorVariableAction = () => {
1402
- const { propType } = (0, import_editor_editing_panel8.useBoundProp)();
1403
- const visible = !!propType && supportsColorVariables(propType);
1819
+ var import_icons12 = require("@elementor/icons");
1820
+ var import_i18n20 = require("@wordpress/i18n");
1821
+ var usePropVariableAction = () => {
1822
+ const { propType, path } = (0, import_editor_editing_panel8.useBoundProp)();
1823
+ const variable = resolveVariableFromPropType(propType);
1404
1824
  return {
1405
- visible,
1406
- icon: import_icons13.ColorFilterIcon,
1407
- title: (0, import_i18n17.__)("Variables", "elementor"),
1825
+ visible: Boolean(variable),
1826
+ icon: import_icons12.ColorFilterIcon,
1827
+ title: (0, import_i18n20.__)("Variables", "elementor"),
1408
1828
  content: ({ close: closePopover }) => {
1409
- return /* @__PURE__ */ React20.createElement(VariableSelectionPopover, { closePopover, propTypeKey: colorVariablePropTypeUtil.key });
1829
+ if (!variable) {
1830
+ return null;
1831
+ }
1832
+ trackOpenVariablePopover(path, variable.variableType);
1833
+ return /* @__PURE__ */ React25.createElement(VariableSelectionPopover, { closePopover, propTypeKey: variable.propTypeUtil.key });
1410
1834
  }
1411
1835
  };
1412
1836
  };
1413
-
1414
- // src/repeater-injections.ts
1415
- var import_editor_controls10 = require("@elementor/editor-controls");
1416
- var import_editor_props4 = require("@elementor/editor-props");
1417
-
1418
- // src/components/variables-repeater-item-slot.tsx
1419
- var React21 = __toESM(require("react"));
1420
- var useColorVariable = (value) => {
1421
- const variableId = value?.value?.color?.value;
1422
- return useVariable(variableId || "");
1423
- };
1424
- var BackgroundRepeaterColorIndicator = ({ value }) => {
1425
- const colorVariable = useColorVariable(value);
1426
- return /* @__PURE__ */ React21.createElement(ColorIndicator, { component: "span", size: "inherit", value: colorVariable?.value });
1427
- };
1428
- var BackgroundRepeaterLabel = ({ value }) => {
1429
- const colorVariable = useColorVariable(value);
1430
- return /* @__PURE__ */ React21.createElement("span", null, colorVariable?.label);
1431
- };
1432
- var BoxShadowRepeaterColorIndicator = ({ value }) => {
1433
- const colorVariable = useColorVariable(value);
1434
- return /* @__PURE__ */ React21.createElement(ColorIndicator, { component: "span", size: "inherit", value: colorVariable?.value });
1435
- };
1436
-
1437
- // src/repeater-injections.ts
1438
- function registerRepeaterInjections() {
1439
- (0, import_editor_controls10.injectIntoRepeaterItemIcon)({
1440
- id: "color-variables-background-icon",
1441
- component: BackgroundRepeaterColorIndicator,
1442
- condition: ({ value: prop }) => {
1443
- return hasAssignedColorVariable(import_editor_props4.backgroundColorOverlayPropTypeUtil.extract(prop)?.color);
1444
- }
1445
- });
1446
- (0, import_editor_controls10.injectIntoRepeaterItemIcon)({
1447
- id: "color-variables-icon",
1448
- component: BoxShadowRepeaterColorIndicator,
1449
- condition: ({ value: prop }) => {
1450
- return hasAssignedColorVariable(import_editor_props4.shadowPropTypeUtil.extract(prop)?.color);
1451
- }
1452
- });
1453
- (0, import_editor_controls10.injectIntoRepeaterItemLabel)({
1454
- id: "color-variables-label",
1455
- component: BackgroundRepeaterLabel,
1456
- condition: ({ value: prop }) => {
1457
- return hasAssignedColorVariable(import_editor_props4.backgroundColorOverlayPropTypeUtil.extract(prop)?.color);
1837
+ var resolveVariableFromPropType = (propType) => {
1838
+ if (propType.kind !== "union") {
1839
+ return void 0;
1840
+ }
1841
+ for (const key of Object.keys(propType.prop_types)) {
1842
+ const variable = getVariableType(key);
1843
+ if (variable) {
1844
+ return variable;
1458
1845
  }
1459
- });
1460
- }
1461
-
1462
- // src/transformers/variable-transformer.ts
1463
- var import_editor_canvas = require("@elementor/editor-canvas");
1464
- var variableTransformer = (0, import_editor_canvas.createTransformer)((value) => {
1465
- if (!value.trim()) {
1466
- return null;
1467
1846
  }
1468
- return `var(--${value})`;
1469
- });
1470
-
1471
- // src/init-color-variables.ts
1472
- var { registerPopoverAction } = import_editor_editing_panel9.controlActionsMenu;
1473
- function initColorVariables() {
1474
- (0, import_editor_editing_panel9.registerControlReplacement)({
1475
- component: ColorVariableControl,
1476
- condition: ({ value }) => hasAssignedColorVariable(value)
1477
- });
1478
- registerPopoverAction({
1479
- id: "color-variables",
1480
- useProps: usePropColorVariableAction
1847
+ return void 0;
1848
+ };
1849
+ var trackOpenVariablePopover = (path, variableType) => {
1850
+ trackVariableEvent({
1851
+ varType: variableType,
1852
+ controlPath: path.join("."),
1853
+ action: "open"
1481
1854
  });
1482
- import_editor_canvas2.styleTransformersRegistry.register(colorVariablePropTypeUtil.key, variableTransformer);
1483
- registerRepeaterInjections();
1484
- }
1855
+ };
1485
1856
 
1486
- // src/init-font-variables.ts
1487
- var import_editor_canvas3 = require("@elementor/editor-canvas");
1488
- var import_editor_editing_panel11 = require("@elementor/editor-editing-panel");
1857
+ // src/register-variable-types.tsx
1858
+ var React28 = __toESM(require("react"));
1859
+ var import_editor_props3 = require("@elementor/editor-props");
1860
+ var import_icons14 = require("@elementor/icons");
1489
1861
 
1490
- // src/controls/font-variable-control.tsx
1491
- var React22 = __toESM(require("react"));
1492
- var import_editor_controls11 = require("@elementor/editor-controls");
1493
- var import_editor_props5 = require("@elementor/editor-props");
1494
- var FontVariableControl = () => {
1495
- const { value: variableValue } = (0, import_editor_controls11.useBoundProp)(fontVariablePropTypeUtil);
1496
- const assignedVariable = useVariable(variableValue);
1497
- if (!assignedVariable) {
1498
- throw new Error(`Global font variable ${variableValue} not found`);
1499
- }
1500
- const isVariableDeleted = assignedVariable?.deleted;
1501
- if (isVariableDeleted) {
1502
- return /* @__PURE__ */ React22.createElement(DeletedVariable, { variable: assignedVariable });
1503
- }
1504
- return /* @__PURE__ */ React22.createElement(
1505
- AssignedVariable,
1862
+ // src/components/fields/color-field.tsx
1863
+ var React26 = __toESM(require("react"));
1864
+ var import_react15 = require("react");
1865
+ var import_ui24 = require("@elementor/ui");
1866
+ var import_i18n21 = require("@wordpress/i18n");
1867
+ var ColorField = ({ value, onChange }) => {
1868
+ const [color, setColor] = (0, import_react15.useState)(value);
1869
+ const [errorMessage, setErrorMessage] = (0, import_react15.useState)("");
1870
+ const defaultRef = (0, import_react15.useRef)(null);
1871
+ const anchorRef = usePopoverContentRef() ?? defaultRef.current;
1872
+ const handleChange = (newValue) => {
1873
+ setColor(newValue);
1874
+ const errorMsg = validateValue(newValue);
1875
+ setErrorMessage(errorMsg);
1876
+ onChange(errorMsg ? "" : newValue);
1877
+ };
1878
+ return /* @__PURE__ */ React26.createElement(import_ui24.Grid, { container: true, gap: 0.75, alignItems: "center" }, /* @__PURE__ */ React26.createElement(import_ui24.Grid, { item: true, xs: 12 }, /* @__PURE__ */ React26.createElement(import_ui24.FormLabel, { size: "tiny" }, (0, import_i18n21.__)("Value", "elementor"))), /* @__PURE__ */ React26.createElement(import_ui24.Grid, { item: true, xs: 12 }, /* @__PURE__ */ React26.createElement(
1879
+ import_ui24.UnstableColorField,
1506
1880
  {
1507
- variable: assignedVariable,
1508
- variablePropTypeUtil: fontVariablePropTypeUtil,
1509
- fallbackPropTypeUtil: import_editor_props5.stringPropTypeUtil
1881
+ size: "tiny",
1882
+ fullWidth: true,
1883
+ value: color,
1884
+ onChange: handleChange,
1885
+ error: errorMessage ?? void 0,
1886
+ slotProps: {
1887
+ colorPicker: {
1888
+ anchorEl: anchorRef,
1889
+ anchorOrigin: { vertical: "top", horizontal: "right" },
1890
+ transformOrigin: { vertical: "top", horizontal: -10 }
1891
+ }
1892
+ }
1510
1893
  }
1511
- );
1894
+ ), errorMessage && /* @__PURE__ */ React26.createElement(import_ui24.FormHelperText, { error: true }, errorMessage)));
1512
1895
  };
1513
1896
 
1514
- // src/hooks/use-prop-font-variable-action.tsx
1515
- var React23 = __toESM(require("react"));
1516
- var import_editor_editing_panel10 = require("@elementor/editor-editing-panel");
1517
- var import_icons14 = require("@elementor/icons");
1518
- var import_i18n18 = require("@wordpress/i18n");
1519
- var usePropFontVariableAction = () => {
1520
- const { propType } = (0, import_editor_editing_panel10.useBoundProp)();
1521
- const visible = !!propType && supportsFontVariables(propType);
1522
- return {
1523
- visible,
1524
- icon: import_icons14.ColorFilterIcon,
1525
- title: (0, import_i18n18.__)("Variables", "elementor"),
1526
- content: ({ close: closePopover }) => {
1527
- return /* @__PURE__ */ React23.createElement(VariableSelectionPopover, { closePopover, propTypeKey: fontVariablePropTypeUtil.key });
1528
- }
1897
+ // src/components/fields/font-field.tsx
1898
+ var React27 = __toESM(require("react"));
1899
+ var import_react16 = require("react");
1900
+ var import_editor_controls10 = require("@elementor/editor-controls");
1901
+ var import_editor_editing_panel9 = require("@elementor/editor-editing-panel");
1902
+ var import_icons13 = require("@elementor/icons");
1903
+ var import_ui25 = require("@elementor/ui");
1904
+ var import_i18n22 = require("@wordpress/i18n");
1905
+ var FontField = ({ value, onChange }) => {
1906
+ const [fontFamily, setFontFamily] = (0, import_react16.useState)(value);
1907
+ const [errorMessage, setErrorMessage] = (0, import_react16.useState)("");
1908
+ const defaultRef = (0, import_react16.useRef)(null);
1909
+ const anchorRef = usePopoverContentRef() ?? defaultRef.current;
1910
+ const fontPopoverState = (0, import_ui25.usePopupState)({ variant: "popover" });
1911
+ const fontFamilies = (0, import_editor_editing_panel9.useFontFamilies)();
1912
+ const sectionWidth = (0, import_editor_editing_panel9.useSectionWidth)();
1913
+ const mapFontSubs = React27.useMemo(() => {
1914
+ return fontFamilies.map(({ label, fonts }) => ({
1915
+ label,
1916
+ items: fonts
1917
+ }));
1918
+ }, [fontFamilies]);
1919
+ const handleChange = (newValue) => {
1920
+ setFontFamily(newValue);
1921
+ const errorMsg = validateValue(newValue);
1922
+ setErrorMessage(errorMsg);
1923
+ onChange(errorMsg ? "" : newValue);
1924
+ };
1925
+ const handleFontFamilyChange = (newFontFamily) => {
1926
+ handleChange(newFontFamily);
1927
+ fontPopoverState.close();
1529
1928
  };
1929
+ return /* @__PURE__ */ React27.createElement(import_ui25.Grid, { container: true, gap: 0.75, alignItems: "center" }, /* @__PURE__ */ React27.createElement(import_ui25.Grid, { item: true, xs: 12 }, /* @__PURE__ */ React27.createElement(import_ui25.FormLabel, { size: "tiny" }, (0, import_i18n22.__)("Value", "elementor"))), /* @__PURE__ */ React27.createElement(import_ui25.Grid, { item: true, xs: 12 }, /* @__PURE__ */ React27.createElement(
1930
+ import_ui25.UnstableTag,
1931
+ {
1932
+ variant: "outlined",
1933
+ label: fontFamily,
1934
+ endIcon: /* @__PURE__ */ React27.createElement(import_icons13.ChevronDownIcon, { fontSize: "tiny" }),
1935
+ ...(0, import_ui25.bindTrigger)(fontPopoverState),
1936
+ fullWidth: true
1937
+ }
1938
+ ), /* @__PURE__ */ React27.createElement(
1939
+ import_ui25.Popover,
1940
+ {
1941
+ disablePortal: true,
1942
+ disableScrollLock: true,
1943
+ anchorEl: anchorRef,
1944
+ anchorOrigin: { vertical: "top", horizontal: "right" },
1945
+ transformOrigin: { vertical: "top", horizontal: -28 },
1946
+ ...(0, import_ui25.bindPopover)(fontPopoverState)
1947
+ },
1948
+ /* @__PURE__ */ React27.createElement(
1949
+ import_editor_controls10.ItemSelector,
1950
+ {
1951
+ itemsList: mapFontSubs,
1952
+ selectedItem: fontFamily,
1953
+ onItemChange: handleFontFamilyChange,
1954
+ onClose: fontPopoverState.close,
1955
+ sectionWidth,
1956
+ title: (0, import_i18n22.__)("Font Family", "elementor"),
1957
+ itemStyle: (item) => ({ fontFamily: item.value }),
1958
+ onDebounce: import_editor_controls10.enqueueFont,
1959
+ icon: import_icons13.TextIcon
1960
+ }
1961
+ )
1962
+ ), errorMessage && /* @__PURE__ */ React27.createElement(import_ui25.FormHelperText, { error: true }, errorMessage)));
1530
1963
  };
1531
1964
 
1532
- // src/init-font-variables.ts
1533
- var { registerPopoverAction: registerPopoverAction2 } = import_editor_editing_panel11.controlActionsMenu;
1534
- function initFontVariables() {
1535
- (0, import_editor_editing_panel11.registerControlReplacement)({
1536
- component: FontVariableControl,
1537
- condition: ({ value }) => hasAssignedFontVariable(value)
1965
+ // src/register-variable-types.tsx
1966
+ function registerVariableTypes() {
1967
+ registerVariableType({
1968
+ valueField: ColorField,
1969
+ icon: import_icons14.BrushIcon,
1970
+ propTypeUtil: colorVariablePropTypeUtil,
1971
+ fallbackPropTypeUtil: import_editor_props3.colorPropTypeUtil,
1972
+ variableType: "color",
1973
+ startIcon: ({ value }) => /* @__PURE__ */ React28.createElement(ColorIndicator, { size: "inherit", component: "span", value })
1538
1974
  });
1539
- registerPopoverAction2({
1540
- id: "font-variables",
1541
- useProps: usePropFontVariableAction
1975
+ registerVariableType({
1976
+ valueField: FontField,
1977
+ icon: import_icons14.TextIcon,
1978
+ propTypeUtil: fontVariablePropTypeUtil,
1979
+ fallbackPropTypeUtil: import_editor_props3.stringPropTypeUtil,
1980
+ variableType: "font"
1542
1981
  });
1543
- import_editor_canvas3.styleTransformersRegistry.register(fontVariablePropTypeUtil.key, variableTransformer);
1544
1982
  }
1545
1983
 
1546
1984
  // src/renderers/style-variables-renderer.tsx
1547
- var React24 = __toESM(require("react"));
1548
- var import_react15 = require("react");
1549
- var import_editor_v1_adapters = require("@elementor/editor-v1-adapters");
1550
- var import_ui21 = require("@elementor/ui");
1985
+ var React29 = __toESM(require("react"));
1986
+ var import_react17 = require("react");
1987
+ var import_editor_v1_adapters3 = require("@elementor/editor-v1-adapters");
1988
+ var import_ui26 = require("@elementor/ui");
1551
1989
 
1552
1990
  // src/sync/get-canvas-iframe-document.ts
1553
1991
  function getCanvasIframeDocument() {
@@ -1566,14 +2004,14 @@ function StyleVariablesRenderer() {
1566
2004
  }
1567
2005
  const cssVariables = convertToCssVariables(styleVariables);
1568
2006
  const wrappedCss = `${VARIABLES_WRAPPER}{${cssVariables}}`;
1569
- return /* @__PURE__ */ React24.createElement(import_ui21.Portal, { container }, /* @__PURE__ */ React24.createElement("style", { "data-e-style-id": "e-variables", key: wrappedCss }, wrappedCss));
2007
+ return /* @__PURE__ */ React29.createElement(import_ui26.Portal, { container }, /* @__PURE__ */ React29.createElement("style", { "data-e-style-id": "e-variables", key: wrappedCss }, wrappedCss));
1570
2008
  }
1571
2009
  function usePortalContainer() {
1572
- return (0, import_editor_v1_adapters.__privateUseListenTo)((0, import_editor_v1_adapters.commandEndEvent)("editor/documents/attach-preview"), () => getCanvasIframeDocument()?.head);
2010
+ return (0, import_editor_v1_adapters3.__privateUseListenTo)((0, import_editor_v1_adapters3.commandEndEvent)("editor/documents/attach-preview"), () => getCanvasIframeDocument()?.head);
1573
2011
  }
1574
2012
  function useStyleVariables() {
1575
- const [variables, setVariables] = (0, import_react15.useState)({});
1576
- (0, import_react15.useEffect)(() => {
2013
+ const [variables, setVariables] = (0, import_react17.useState)({});
2014
+ (0, import_react17.useEffect)(() => {
1577
2015
  const unsubscribe = styleVariablesRepository.subscribe(setVariables);
1578
2016
  return () => {
1579
2017
  unsubscribe();
@@ -1581,22 +2019,96 @@ function useStyleVariables() {
1581
2019
  }, []);
1582
2020
  return variables;
1583
2021
  }
2022
+ function cssVariableDeclaration(key, variable) {
2023
+ const variableName = variable?.deleted ? key : variable.label;
2024
+ const value = variable.value;
2025
+ return `--${variableName}:${value};`;
2026
+ }
1584
2027
  function convertToCssVariables(variables) {
1585
- return Object.entries(variables).map(([key, value]) => `--${key}:${value};`).join("");
2028
+ const listOfVariables = Object.entries(variables);
2029
+ return listOfVariables.map(([key, variable]) => cssVariableDeclaration(key, variable)).join("");
1586
2030
  }
1587
2031
 
2032
+ // src/repeater-injections.ts
2033
+ var import_editor_controls11 = require("@elementor/editor-controls");
2034
+ var import_editor_props4 = require("@elementor/editor-props");
2035
+
2036
+ // src/components/variables-repeater-item-slot.tsx
2037
+ var React30 = __toESM(require("react"));
2038
+ var useColorVariable = (value) => {
2039
+ const variableId = value?.value?.color?.value;
2040
+ return useVariable(variableId || "");
2041
+ };
2042
+ var BackgroundRepeaterColorIndicator = ({ value }) => {
2043
+ const colorVariable = useColorVariable(value);
2044
+ return /* @__PURE__ */ React30.createElement(ColorIndicator, { component: "span", size: "inherit", value: colorVariable?.value });
2045
+ };
2046
+ var BackgroundRepeaterLabel = ({ value }) => {
2047
+ const colorVariable = useColorVariable(value);
2048
+ return /* @__PURE__ */ React30.createElement("span", null, colorVariable?.label);
2049
+ };
2050
+ var BoxShadowRepeaterColorIndicator = ({ value }) => {
2051
+ const colorVariable = useColorVariable(value);
2052
+ return /* @__PURE__ */ React30.createElement(ColorIndicator, { component: "span", size: "inherit", value: colorVariable?.value });
2053
+ };
2054
+
2055
+ // src/repeater-injections.ts
2056
+ function registerRepeaterInjections() {
2057
+ (0, import_editor_controls11.injectIntoRepeaterItemIcon)({
2058
+ id: "color-variables-background-icon",
2059
+ component: BackgroundRepeaterColorIndicator,
2060
+ condition: ({ value: prop }) => {
2061
+ return hasAssignedColorVariable(import_editor_props4.backgroundColorOverlayPropTypeUtil.extract(prop)?.color);
2062
+ }
2063
+ });
2064
+ (0, import_editor_controls11.injectIntoRepeaterItemIcon)({
2065
+ id: "color-variables-icon",
2066
+ component: BoxShadowRepeaterColorIndicator,
2067
+ condition: ({ value: prop }) => {
2068
+ return hasAssignedColorVariable(import_editor_props4.shadowPropTypeUtil.extract(prop)?.color);
2069
+ }
2070
+ });
2071
+ (0, import_editor_controls11.injectIntoRepeaterItemLabel)({
2072
+ id: "color-variables-label",
2073
+ component: BackgroundRepeaterLabel,
2074
+ condition: ({ value: prop }) => {
2075
+ return hasAssignedColorVariable(import_editor_props4.backgroundColorOverlayPropTypeUtil.extract(prop)?.color);
2076
+ }
2077
+ });
2078
+ }
2079
+ var hasAssignedColorVariable = (propValue) => {
2080
+ return !!colorVariablePropTypeUtil.isValid(propValue);
2081
+ };
2082
+
1588
2083
  // src/init.ts
2084
+ var { registerPopoverAction } = import_editor_editing_panel10.controlActionsMenu;
1589
2085
  function init() {
1590
- initColorVariables();
1591
- initFontVariables();
2086
+ registerVariableTypes();
2087
+ registerRepeaterInjections();
2088
+ (0, import_editor_editing_panel10.registerControlReplacement)({
2089
+ component: VariableControl,
2090
+ condition: ({ value }) => hasAssignedVariable(value)
2091
+ });
2092
+ registerPopoverAction({
2093
+ id: "variables",
2094
+ useProps: usePropVariableAction
2095
+ });
1592
2096
  service.init();
1593
2097
  (0, import_editor.injectIntoTop)({
1594
2098
  id: "canvas-style-variables-render",
1595
2099
  component: StyleVariablesRenderer
1596
2100
  });
2101
+ (0, import_editor_panels2.__registerPanel)(panel);
2102
+ }
2103
+ function hasAssignedVariable(propValue) {
2104
+ if (propValue && typeof propValue === "object" && "$$type" in propValue) {
2105
+ return hasVariableType(propValue.$$type);
2106
+ }
2107
+ return false;
1597
2108
  }
1598
2109
  // Annotate the CommonJS export names for ESM import in node:
1599
2110
  0 && (module.exports = {
1600
- init
2111
+ init,
2112
+ registerVariableType
1601
2113
  });
1602
2114
  //# sourceMappingURL=index.js.map