@elementor/editor-variables 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # @elementor/editor-variables
2
2
 
3
+ ## 0.10.0
4
+
5
+ ### Minor Changes
6
+
7
+ - dc91d6b: client side storage and server api-connector
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [a3ba5ef]
12
+ - Updated dependencies [9b6dbdd]
13
+ - Updated dependencies [7feedb4]
14
+ - Updated dependencies [1edd821]
15
+ - @elementor/editor-editing-panel@1.43.0
16
+ - @elementor/editor-controls@0.34.2
17
+
18
+ ## 0.9.0
19
+
20
+ ### Minor Changes
21
+
22
+ - 2ea62e2: Reactive rendering variables style on canvas
23
+
24
+ ### Patch Changes
25
+
26
+ - Updated dependencies [cd4c3fe]
27
+ - Updated dependencies [b7369f2]
28
+ - Updated dependencies [8f3a61b]
29
+ - Updated dependencies [e732d81]
30
+ - Updated dependencies [8dca168]
31
+ - @elementor/editor-editing-panel@1.42.0
32
+ - @elementor/editor-controls@0.34.1
33
+
3
34
  ## 0.8.0
4
35
 
5
36
  ### Minor Changes
package/dist/index.js CHANGED
@@ -34,6 +34,9 @@ __export(index_exports, {
34
34
  });
35
35
  module.exports = __toCommonJS(index_exports);
36
36
 
37
+ // src/init.ts
38
+ var import_editor = require("@elementor/editor");
39
+
37
40
  // src/init-color-variables.ts
38
41
  var import_editor_canvas2 = require("@elementor/editor-canvas");
39
42
  var import_editor_editing_panel2 = require("@elementor/editor-editing-panel");
@@ -58,39 +61,82 @@ var import_ui3 = require("@elementor/ui");
58
61
 
59
62
  // src/hooks/use-prop-variables.ts
60
63
  var import_react = require("react");
61
- var usePropVariables = (propTypeKey) => {
62
- return (0, import_react.useMemo)(() => normalizeVariables(propTypeKey), [propTypeKey]);
64
+
65
+ // src/create-style-variables-repository.ts
66
+ var createStyleVariablesRepository = () => {
67
+ const variables2 = {};
68
+ let subscription;
69
+ const subscribe = (cb) => {
70
+ subscription = cb;
71
+ return () => {
72
+ subscription = () => {
73
+ };
74
+ };
75
+ };
76
+ const notify = () => {
77
+ if (typeof subscription === "function") {
78
+ subscription({ ...variables2 });
79
+ }
80
+ };
81
+ const shouldUpdate = (key, newValue) => {
82
+ return !(key in variables2) || variables2[key] !== newValue;
83
+ };
84
+ const applyUpdates = (updatedVars) => {
85
+ let hasChanges = false;
86
+ for (const [key, { value }] of Object.entries(updatedVars)) {
87
+ if (shouldUpdate(key, value)) {
88
+ variables2[key] = value;
89
+ hasChanges = true;
90
+ }
91
+ }
92
+ return hasChanges;
93
+ };
94
+ const update = (updatedVars) => {
95
+ if (applyUpdates(updatedVars)) {
96
+ notify();
97
+ }
98
+ };
99
+ return {
100
+ subscribe,
101
+ update
102
+ };
63
103
  };
64
- var useVariable = (propTypeKey, key) => {
65
- if (!variables[propTypeKey]?.[key]) {
104
+
105
+ // src/style-variables-repository.ts
106
+ var styleVariablesRepository = createStyleVariablesRepository();
107
+
108
+ // src/hooks/use-prop-variables.ts
109
+ var usePropVariables = (propKey) => {
110
+ return (0, import_react.useMemo)(() => normalizeVariables(propKey), [propKey]);
111
+ };
112
+ var useVariable = (key) => {
113
+ if (!variables?.[key]) {
66
114
  return null;
67
115
  }
68
116
  return {
69
- ...variables[propTypeKey][key],
117
+ ...variables[key],
70
118
  key
71
119
  };
72
120
  };
73
- var normalizeVariables = (propTypeKey) => {
74
- return Object.entries(variables[propTypeKey] || {}).map(([key, { label, value }]) => ({
121
+ var normalizeVariables = (propKey) => {
122
+ return Object.entries(variables).filter(([, { type }]) => type === propKey).map(([key, { label, value }]) => ({
75
123
  key,
76
124
  label,
77
125
  value
78
126
  }));
79
127
  };
80
- var createVariable = (propTypeKey, variable) => {
81
- const id = generateId("e-gv", Object.keys(variables[propTypeKey]).length);
82
- const newVariable = {
83
- value: variable.value,
84
- label: variable.label,
85
- key: propTypeKey
86
- };
87
- variables[propTypeKey][id] = newVariable || {};
128
+ var createVariable = (variable) => {
129
+ const id = generateId();
130
+ variables[id] = variable;
131
+ styleVariablesRepository.update({
132
+ [id]: variable
133
+ });
88
134
  return id;
89
135
  };
90
136
  var variables = window?.ElementorV4Variables || {};
91
- var generateId = (prefix, variablesCount) => {
137
+ var generateId = (prefix = "e-gv") => {
92
138
  const randomHex = Math.random().toString(16).slice(2, 9);
93
- return `${prefix}${randomHex}${variablesCount}`;
139
+ return `${prefix}${randomHex}`;
94
140
  };
95
141
 
96
142
  // src/prop-types/color-variable-prop-type.ts
@@ -113,15 +159,15 @@ var StyledMenuItem = (0, import_ui2.styled)(import_ui2.MenuItem)(() => ({
113
159
  var ColorVariablesSelection = ({ onSelect }) => {
114
160
  const { value: variable, setValue: setVariable } = (0, import_editor_controls.useBoundProp)(colorVariablePropTypeUtil);
115
161
  const variables2 = usePropVariables(colorVariablePropTypeUtil.key);
116
- const handleSetColorVariable = (newValue) => {
117
- setVariable(newValue.key);
162
+ const handleSetColorVariable = (key) => {
163
+ setVariable(key);
118
164
  onSelect?.();
119
165
  };
120
166
  return /* @__PURE__ */ React.createElement(import_react2.Fragment, null, /* @__PURE__ */ React.createElement(import_ui3.Divider, null), /* @__PURE__ */ React.createElement(import_ui3.Box, { sx: { overflowY: "auto", height: 260, width: 220 } }, /* @__PURE__ */ React.createElement(import_ui3.MenuList, { role: "listbox", tabIndex: 0 }, variables2.map(({ value, label, key }) => /* @__PURE__ */ React.createElement(
121
167
  StyledMenuItem,
122
168
  {
123
169
  key,
124
- onClick: () => handleSetColorVariable({ value, label, key }),
170
+ onClick: () => handleSetColorVariable(key),
125
171
  selected: key === variable
126
172
  },
127
173
  /* @__PURE__ */ React.createElement(import_ui3.ListItemIcon, null, /* @__PURE__ */ React.createElement(ColorIndicator, { size: "inherit", component: "span", value })),
@@ -182,7 +228,11 @@ var ColorVariableCreation = ({ popupState }) => {
182
228
  popupState.close();
183
229
  };
184
230
  const handleCreate = () => {
185
- const key = createVariable(colorVariablePropTypeUtil.key, { label, value: color });
231
+ const key = createVariable({
232
+ value: color,
233
+ label,
234
+ type: colorVariablePropTypeUtil.key
235
+ });
186
236
  setVariable(key);
187
237
  closePopover();
188
238
  };
@@ -287,7 +337,7 @@ var VariablesSelectionPopover = ({
287
337
  var ColorVariablesSelectionControl = () => {
288
338
  const { setValue } = (0, import_editor_controls3.useBoundProp)();
289
339
  const { value: variableValue } = (0, import_editor_controls3.useBoundProp)(colorVariablePropTypeUtil);
290
- const selectedVariable = useVariable(colorVariablePropTypeUtil.key, variableValue);
340
+ const selectedVariable = useVariable(variableValue);
291
341
  if (!selectedVariable) {
292
342
  throw new Error(`Global color variable ${variableValue} not found`);
293
343
  }
@@ -383,15 +433,15 @@ var import_ui6 = require("@elementor/ui");
383
433
  var FontVariablesSelection = ({ onSelect }) => {
384
434
  const { value: variable, setValue: setVariable } = (0, import_editor_controls4.useBoundProp)(fontVariablePropTypeUtil);
385
435
  const variables2 = usePropVariables(fontVariablePropTypeUtil.key);
386
- const handleSetVariable = (newValue) => {
387
- setVariable(newValue.key);
436
+ const handleSetVariable = (key) => {
437
+ setVariable(key);
388
438
  onSelect?.();
389
439
  };
390
440
  return /* @__PURE__ */ React6.createElement(import_react5.Fragment, null, /* @__PURE__ */ React6.createElement(import_ui6.Divider, null), /* @__PURE__ */ React6.createElement(import_ui6.Box, { sx: { overflowY: "auto", height: 260, width: 220 } }, /* @__PURE__ */ React6.createElement(import_ui6.MenuList, { role: "listbox", tabIndex: 0 }, variables2.map(({ value, label, key }) => /* @__PURE__ */ React6.createElement(
391
441
  StyledMenuItem,
392
442
  {
393
443
  key,
394
- onClick: () => handleSetVariable({ value, label, key }),
444
+ onClick: () => handleSetVariable(key),
395
445
  selected: key === variable
396
446
  },
397
447
  /* @__PURE__ */ React6.createElement(import_ui6.ListItemIcon, null, /* @__PURE__ */ React6.createElement(import_icons5.TextIcon, null)),
@@ -428,7 +478,7 @@ var FontVariablesSelection = ({ onSelect }) => {
428
478
  var FontVariablesSelectionControl = () => {
429
479
  const { setValue: setFontFamily } = (0, import_editor_controls5.useBoundProp)();
430
480
  const { value: variableValue } = (0, import_editor_controls5.useBoundProp)(fontVariablePropTypeUtil);
431
- const selectedVariable = useVariable(fontVariablePropTypeUtil.key, variableValue);
481
+ const selectedVariable = useVariable(variableValue);
432
482
  if (!selectedVariable) {
433
483
  throw new Error(`Global font variable ${variableValue} not found`);
434
484
  }
@@ -468,10 +518,238 @@ function initFontVariables() {
468
518
  import_editor_canvas3.styleTransformersRegistry.register(fontVariablePropTypeUtil.key, variableTransformer);
469
519
  }
470
520
 
521
+ // src/renderers/style-variables-renderer.tsx
522
+ var React9 = __toESM(require("react"));
523
+ var import_react6 = require("react");
524
+ var import_editor_v1_adapters = require("@elementor/editor-v1-adapters");
525
+ var import_ui7 = require("@elementor/ui");
526
+
527
+ // src/sync/get-canvas-iframe-document.ts
528
+ function getCanvasIframeDocument() {
529
+ const extendedWindow = window;
530
+ return extendedWindow.elementor?.$preview?.[0]?.contentDocument;
531
+ }
532
+
533
+ // src/renderers/style-variables-renderer.tsx
534
+ var VARIABLES_WRAPPER = "body";
535
+ function StyleVariablesRenderer() {
536
+ const container = usePortalContainer();
537
+ const styleVariables = useStyleVariables();
538
+ const hasVariables = Object.keys(styleVariables).length > 0;
539
+ if (!container || !hasVariables) {
540
+ return null;
541
+ }
542
+ const cssVariables = convertToCssVariables(styleVariables);
543
+ const wrappedCss = `${VARIABLES_WRAPPER}{${cssVariables}}`;
544
+ return /* @__PURE__ */ React9.createElement(import_ui7.Portal, { container }, /* @__PURE__ */ React9.createElement("style", { "data-e-style-id": "e-variables", key: wrappedCss }, wrappedCss));
545
+ }
546
+ function usePortalContainer() {
547
+ return (0, import_editor_v1_adapters.__privateUseListenTo)((0, import_editor_v1_adapters.commandEndEvent)("editor/documents/attach-preview"), () => getCanvasIframeDocument()?.head);
548
+ }
549
+ function useStyleVariables() {
550
+ const [variables2, setVariables] = (0, import_react6.useState)({});
551
+ (0, import_react6.useEffect)(() => {
552
+ const unsubscribe = styleVariablesRepository.subscribe(setVariables);
553
+ return () => {
554
+ unsubscribe();
555
+ };
556
+ }, []);
557
+ return variables2;
558
+ }
559
+ function convertToCssVariables(variables2) {
560
+ return Object.entries(variables2).map(([key, value]) => `--${key}:${value};`).join("");
561
+ }
562
+
563
+ // src/api.ts
564
+ var import_http_client = require("@elementor/http-client");
565
+ var BASE_PATH = "elementor/v1/variables";
566
+ var apiClient = {
567
+ list: () => {
568
+ return (0, import_http_client.httpService)().get(BASE_PATH + "/list");
569
+ },
570
+ create: (type, label, value) => {
571
+ return (0, import_http_client.httpService)().post(BASE_PATH + "/create", {
572
+ type,
573
+ label,
574
+ value
575
+ });
576
+ },
577
+ update: (id, label, value) => {
578
+ return (0, import_http_client.httpService)().put(BASE_PATH + "/update", {
579
+ id,
580
+ label,
581
+ value
582
+ });
583
+ },
584
+ delete: (id) => {
585
+ return (0, import_http_client.httpService)().post(BASE_PATH + "/delete", { id });
586
+ },
587
+ restore: (id) => {
588
+ return (0, import_http_client.httpService)().post(BASE_PATH + "/restore", { id });
589
+ }
590
+ };
591
+
592
+ // src/storage.ts
593
+ var STORAGE_KEY = "elementor-global-variables";
594
+ var STORAGE_WATERMARK_KEY = "elementor-global-variables-watermark";
595
+ var OP_RW = "RW";
596
+ var OP_RO = "RO";
597
+ var Storage = class {
598
+ state;
599
+ constructor() {
600
+ this.state = {
601
+ watermark: -1,
602
+ variables: {}
603
+ };
604
+ }
605
+ load() {
606
+ this.state.watermark = parseInt(localStorage.getItem(STORAGE_WATERMARK_KEY) || "-1");
607
+ this.state.variables = JSON.parse(localStorage.getItem(STORAGE_KEY) || "{}");
608
+ return this.state.variables;
609
+ }
610
+ fill(variables2, watermark) {
611
+ this.state.watermark = watermark;
612
+ this.state.variables = variables2;
613
+ localStorage.setItem(STORAGE_WATERMARK_KEY, this.state.watermark.toString());
614
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(this.state.variables));
615
+ }
616
+ add(id, variable) {
617
+ this.load();
618
+ this.state.variables[id] = variable;
619
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(this.state.variables));
620
+ }
621
+ update(id, variable) {
622
+ this.load();
623
+ this.state.variables[id] = variable;
624
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(this.state.variables));
625
+ }
626
+ watermark(watermark) {
627
+ this.state.watermark = watermark;
628
+ localStorage.setItem(STORAGE_WATERMARK_KEY, this.state.watermark.toString());
629
+ }
630
+ watermarkDiff(operation, newWatermark) {
631
+ const diff = newWatermark - this.state.watermark;
632
+ if (OP_RW === operation) {
633
+ return 1 !== diff;
634
+ }
635
+ if (OP_RO === operation) {
636
+ return 0 !== diff;
637
+ }
638
+ return false;
639
+ }
640
+ };
641
+
642
+ // src/service.ts
643
+ var storage = new Storage();
644
+ var service = {
645
+ variables: () => {
646
+ return storage.load();
647
+ },
648
+ init: () => {
649
+ service.load();
650
+ },
651
+ load: () => {
652
+ return apiClient.list().then((response) => {
653
+ const { success, data: payload } = response.data;
654
+ if (!success) {
655
+ throw new Error("Unexpected response from server");
656
+ }
657
+ return payload;
658
+ }).then((data) => {
659
+ const { variables: variables2, watermark } = data;
660
+ storage.fill(variables2, watermark);
661
+ return variables2;
662
+ });
663
+ },
664
+ create: ({ type, label, value }) => {
665
+ return apiClient.create(type, label, value).then((response) => {
666
+ const { success, data: payload } = response.data;
667
+ if (!success) {
668
+ throw new Error("Unexpected response from server");
669
+ }
670
+ return payload;
671
+ }).then((data) => {
672
+ const { variable, watermark } = data;
673
+ handleWatermark(OP_RW, watermark);
674
+ const { id: variableId, ...createdVariable } = variable;
675
+ storage.add(variableId, createdVariable);
676
+ return {
677
+ id: variableId,
678
+ variable: createdVariable
679
+ };
680
+ });
681
+ },
682
+ update: (id, { label, value }) => {
683
+ return apiClient.update(id, label, value).then((response) => {
684
+ const { success, data: payload } = response.data;
685
+ if (!success) {
686
+ throw new Error("Unexpected response from server");
687
+ }
688
+ return payload;
689
+ }).then((data) => {
690
+ const { variable, watermark } = data;
691
+ handleWatermark(OP_RW, watermark);
692
+ const { id: variableId, ...updatedVariable } = variable;
693
+ storage.update(variableId, updatedVariable);
694
+ return {
695
+ id: variableId,
696
+ variable: updatedVariable
697
+ };
698
+ });
699
+ },
700
+ delete: (id) => {
701
+ return apiClient.delete(id).then((response) => {
702
+ const { success, data: payload } = response.data;
703
+ if (!success) {
704
+ throw new Error("Unexpected response from server");
705
+ }
706
+ return payload;
707
+ }).then((data) => {
708
+ const { variable, watermark } = data;
709
+ handleWatermark(OP_RW, watermark);
710
+ const { id: variableId, ...deletedVariable } = variable;
711
+ storage.update(variableId, deletedVariable);
712
+ return {
713
+ id: variableId,
714
+ variable: deletedVariable
715
+ };
716
+ });
717
+ },
718
+ restore: (id) => {
719
+ return apiClient.restore(id).then((response) => {
720
+ const { success, data: payload } = response.data;
721
+ if (!success) {
722
+ throw new Error("Unexpected response from server");
723
+ }
724
+ return payload;
725
+ }).then((data) => {
726
+ const { variable, watermark } = data;
727
+ handleWatermark(OP_RW, watermark);
728
+ const { id: variableId, ...restoredVariable } = variable;
729
+ storage.update(variableId, restoredVariable);
730
+ return {
731
+ id: variableId,
732
+ variable: restoredVariable
733
+ };
734
+ });
735
+ }
736
+ };
737
+ var handleWatermark = (operation, newWatermark) => {
738
+ if (storage.watermarkDiff(operation, newWatermark)) {
739
+ setTimeout(() => service.load(), 500);
740
+ }
741
+ storage.watermark(newWatermark);
742
+ };
743
+
471
744
  // src/init.ts
472
745
  function init() {
473
746
  initColorVariables();
474
747
  initFontVariables();
748
+ service.init();
749
+ (0, import_editor.injectIntoTop)({
750
+ id: "canvas-style-variables-render",
751
+ component: StyleVariablesRenderer
752
+ });
475
753
  }
476
754
  // Annotate the CommonJS export names for ESM import in node:
477
755
  0 && (module.exports = {