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