@elementor/editor-global-classes 0.20.5 → 0.21.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/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/init.ts
2
2
  import { injectIntoLogic } from "@elementor/editor";
3
- import { injectIntoClassSelectorActions } from "@elementor/editor-editing-panel";
3
+ import { injectIntoClassSelectorActions, registerStyleProviderToColors } from "@elementor/editor-editing-panel";
4
4
  import { __registerPanel as registerPanel } from "@elementor/editor-panels";
5
5
  import { stylesRepository } from "@elementor/editor-styles-repository";
6
6
  import { __privateListenTo as listenTo, v1ReadyEvent } from "@elementor/editor-v1-adapters";
@@ -63,6 +63,69 @@ import {
63
63
  __createSelector as createSelector,
64
64
  __createSlice as createSlice
65
65
  } from "@elementor/store";
66
+
67
+ // src/utils/snapshot-history.ts
68
+ function createLink({ value, next, prev }) {
69
+ return {
70
+ value,
71
+ prev: prev || null,
72
+ next: next || null
73
+ };
74
+ }
75
+ var SnapshotHistory = class _SnapshotHistory {
76
+ constructor(namespace) {
77
+ this.namespace = namespace;
78
+ }
79
+ static registry = {};
80
+ static get(namespace) {
81
+ if (!_SnapshotHistory.registry[namespace]) {
82
+ _SnapshotHistory.registry[namespace] = new _SnapshotHistory(namespace);
83
+ }
84
+ return _SnapshotHistory.registry[namespace];
85
+ }
86
+ first = null;
87
+ current = null;
88
+ transform(item) {
89
+ return JSON.parse(JSON.stringify(item));
90
+ }
91
+ reset() {
92
+ this.first = this.current = null;
93
+ }
94
+ prev() {
95
+ if (!this.current || this.current === this.first) {
96
+ return null;
97
+ }
98
+ this.current = this.current.prev;
99
+ return this.current?.value || null;
100
+ }
101
+ isLast() {
102
+ return !this.current || !this.current.next;
103
+ }
104
+ next(value) {
105
+ if (value) {
106
+ if (!this.current) {
107
+ this.first = createLink({ value: this.transform(value) });
108
+ this.current = this.first;
109
+ return this.current.value;
110
+ }
111
+ const nextLink = createLink({
112
+ value: this.transform(value),
113
+ prev: this.current
114
+ });
115
+ this.current.next = nextLink;
116
+ this.current = nextLink;
117
+ return this.current.value;
118
+ }
119
+ if (!this.current || !this.current.next) {
120
+ return null;
121
+ }
122
+ this.current = this.current.next;
123
+ return this.current.value;
124
+ }
125
+ };
126
+
127
+ // src/store.ts
128
+ var localHistory = SnapshotHistory.get("global-classes");
66
129
  var initialState = {
67
130
  data: { items: {}, order: [] },
68
131
  initialData: {
@@ -85,11 +148,13 @@ var slice = createSlice({
85
148
  state.isDirty = false;
86
149
  },
87
150
  add(state, { payload }) {
151
+ localHistory.next(state.data);
88
152
  state.data.items[payload.id] = payload;
89
153
  state.data.order.unshift(payload.id);
90
154
  state.isDirty = true;
91
155
  },
92
156
  delete(state, { payload }) {
157
+ localHistory.next(state.data);
93
158
  state.data.items = Object.fromEntries(
94
159
  Object.entries(state.data.items).filter(([id2]) => id2 !== payload)
95
160
  );
@@ -97,10 +162,12 @@ var slice = createSlice({
97
162
  state.isDirty = true;
98
163
  },
99
164
  setOrder(state, { payload }) {
165
+ localHistory.next(state.data);
100
166
  state.data.order = payload;
101
167
  state.isDirty = true;
102
168
  },
103
169
  update(state, { payload }) {
170
+ localHistory.next(state.data);
104
171
  const style = state.data.items[payload.style.id];
105
172
  const mergedData = {
106
173
  ...style,
@@ -116,6 +183,7 @@ var slice = createSlice({
116
183
  if (!style) {
117
184
  throw new GlobalClassNotFoundError({ context: { styleId: payload.id } });
118
185
  }
186
+ localHistory.next(state.data);
119
187
  const variant = getVariantByMeta(style, payload.meta);
120
188
  if (variant) {
121
189
  variant.props = mergeProps(variant.props, payload.props);
@@ -129,10 +197,38 @@ var slice = createSlice({
129
197
  },
130
198
  reset(state, { payload: { context: context2 } }) {
131
199
  if (context2 === "frontend") {
200
+ localHistory.reset();
132
201
  state.initialData.frontend = state.data;
133
202
  state.isDirty = false;
134
203
  }
135
204
  state.initialData.preview = state.data;
205
+ },
206
+ undo(state) {
207
+ if (localHistory.isLast()) {
208
+ localHistory.next(state.data);
209
+ }
210
+ const data = localHistory.prev();
211
+ if (data) {
212
+ state.data = data;
213
+ state.isDirty = true;
214
+ } else {
215
+ state.data = state.initialData.preview;
216
+ }
217
+ },
218
+ resetToInitialState(state, { payload: { context: context2 } }) {
219
+ localHistory.reset();
220
+ state.data = state.initialData[context2];
221
+ state.isDirty = false;
222
+ },
223
+ redo(state) {
224
+ const data = localHistory.next();
225
+ if (localHistory.isLast()) {
226
+ localHistory.prev();
227
+ }
228
+ if (data) {
229
+ state.data = data;
230
+ state.isDirty = true;
231
+ }
136
232
  }
137
233
  }
138
234
  });
@@ -151,8 +247,9 @@ var selectClass = (state, id2) => state[SLICE_NAME].data.items[id2] ?? null;
151
247
 
152
248
  // src/global-classes-styles-provider.ts
153
249
  var MAX_CLASSES = 50;
250
+ var GLOBAL_CLASSES_PROVIDER_KEY = "global-classes";
154
251
  var globalClassesStylesProvider = createStylesProvider({
155
- key: "global-classes",
252
+ key: GLOBAL_CLASSES_PROVIDER_KEY,
156
253
  priority: 30,
157
254
  limit: MAX_CLASSES,
158
255
  labels: {
@@ -212,7 +309,7 @@ var globalClassesStylesProvider = createStylesProvider({
212
309
 
213
310
  // src/components/class-manager/class-manager-panel.tsx
214
311
  import * as React7 from "react";
215
- import { useEffect } from "react";
312
+ import { useEffect as useEffect2 } from "react";
216
313
  import { setDocumentModifiedStatus } from "@elementor/editor-documents";
217
314
  import {
218
315
  __createPanel as createPanel,
@@ -226,7 +323,16 @@ import { ThemeProvider } from "@elementor/editor-ui";
226
323
  import { changeEditMode } from "@elementor/editor-v1-adapters";
227
324
  import { XIcon } from "@elementor/icons";
228
325
  import { useMutation } from "@elementor/query";
229
- import { Alert, Box as Box4, Button as Button3, ErrorBoundary, IconButton as IconButton2, Stack as Stack2 } from "@elementor/ui";
326
+ import { __dispatch as dispatch4 } from "@elementor/store";
327
+ import {
328
+ Alert,
329
+ Box as Box4,
330
+ Button as Button3,
331
+ DialogHeader,
332
+ ErrorBoundary,
333
+ IconButton as IconButton2,
334
+ Stack as Stack2
335
+ } from "@elementor/ui";
230
336
  import { __ as __5 } from "@wordpress/i18n";
231
337
 
232
338
  // src/hooks/use-dirty-state.ts
@@ -375,7 +481,7 @@ var FlippedColorSwatchIcon = ({ sx, ...props }) => /* @__PURE__ */ React2.create
375
481
 
376
482
  // src/components/class-manager/global-classes-list.tsx
377
483
  import * as React5 from "react";
378
- import { useRef } from "react";
484
+ import { useEffect, useRef } from "react";
379
485
  import { validateStyleLabel } from "@elementor/editor-styles-repository";
380
486
  import { EditableField, EllipsisWithTooltip, MenuListItem, useEditable, WarningInfotip } from "@elementor/editor-ui";
381
487
  import { DotsVerticalIcon } from "@elementor/icons";
@@ -522,14 +628,31 @@ var SortableItemIndicator = styled(Box2)`
522
628
  // src/components/class-manager/global-classes-list.tsx
523
629
  var GlobalClassesList = ({ disabled }) => {
524
630
  const cssClasses = useOrderedClasses();
525
- const dispatch4 = useDispatch();
631
+ const dispatch5 = useDispatch();
526
632
  const [classesOrder, reorderClasses] = useReorder();
633
+ useEffect(() => {
634
+ const handler = (event) => {
635
+ if (event.key === "z" && (event.ctrlKey || event.metaKey)) {
636
+ event.stopImmediatePropagation();
637
+ event.preventDefault();
638
+ if (event.shiftKey) {
639
+ dispatch5(slice.actions.redo());
640
+ return;
641
+ }
642
+ dispatch5(slice.actions.undo());
643
+ }
644
+ };
645
+ window.addEventListener("keydown", handler, {
646
+ capture: true
647
+ });
648
+ return () => window.removeEventListener("keydown", handler);
649
+ }, [dispatch5]);
527
650
  if (!cssClasses?.length) {
528
651
  return /* @__PURE__ */ React5.createElement(EmptyState, null);
529
652
  }
530
653
  return /* @__PURE__ */ React5.createElement(DeleteConfirmationProvider, null, /* @__PURE__ */ React5.createElement(List, { sx: { display: "flex", flexDirection: "column", gap: 0.5 } }, /* @__PURE__ */ React5.createElement(SortableProvider, { value: classesOrder, onChange: reorderClasses }, cssClasses?.map(({ id: id2, label }) => {
531
654
  const renameClass = (newLabel) => {
532
- dispatch4(
655
+ dispatch5(
533
656
  slice.actions.update({
534
657
  style: {
535
658
  id: id2,
@@ -552,10 +675,10 @@ var GlobalClassesList = ({ disabled }) => {
552
675
  }))));
553
676
  };
554
677
  var useReorder = () => {
555
- const dispatch4 = useDispatch();
678
+ const dispatch5 = useDispatch();
556
679
  const order = useClassesOrder();
557
680
  const reorder = (newIds) => {
558
- dispatch4(slice.actions.setOrder(newIds));
681
+ dispatch5(slice.actions.setOrder(newIds));
559
682
  };
560
683
  return [order, reorder];
561
684
  };
@@ -748,13 +871,13 @@ var SaveChangesDialogContent = ({ children }) => /* @__PURE__ */ React6.createEl
748
871
  var SaveChangesDialogContentText = (props) => /* @__PURE__ */ React6.createElement(DialogContentText2, { variant: "body2", color: "textPrimary", display: "flex", flexDirection: "column", ...props });
749
872
  var SaveChangesDialogActions = ({ actions }) => {
750
873
  const [isConfirming, setIsConfirming] = useState3(false);
751
- const { cancel, confirm } = actions;
874
+ const { cancel, confirm, discard } = actions;
752
875
  const onConfirm = async () => {
753
876
  setIsConfirming(true);
754
877
  await confirm.action();
755
878
  setIsConfirming(false);
756
879
  };
757
- return /* @__PURE__ */ React6.createElement(DialogActions2, null, /* @__PURE__ */ React6.createElement(Button2, { variant: "text", color: "secondary", onClick: cancel.action }, cancel.label), /* @__PURE__ */ React6.createElement(Button2, { variant: "contained", color: "secondary", onClick: onConfirm, loading: isConfirming }, confirm.label));
880
+ return /* @__PURE__ */ React6.createElement(DialogActions2, null, cancel && /* @__PURE__ */ React6.createElement(Button2, { variant: "text", color: "secondary", onClick: cancel.action }, cancel.label), discard && /* @__PURE__ */ React6.createElement(Button2, { variant: "text", color: "secondary", onClick: discard.action }, discard.label), /* @__PURE__ */ React6.createElement(Button2, { variant: "contained", color: "secondary", onClick: onConfirm, loading: isConfirming }, confirm.label));
758
881
  };
759
882
  SaveChangesDialog.Title = SaveChangesDialogTitle;
760
883
  SaveChangesDialog.Content = SaveChangesDialogContent;
@@ -787,6 +910,10 @@ function ClassManagerPanel() {
787
910
  const { close: closePanel } = usePanelActions();
788
911
  const { open: openSaveChangesDialog, close: closeSaveChangesDialog, isOpen: isSaveChangesDialogOpen } = useDialog();
789
912
  const { mutateAsync: publish, isPending: isPublishing } = usePublish();
913
+ const resetAndClosePanel = () => {
914
+ dispatch4(slice.actions.resetToInitialState({ context: "frontend" }));
915
+ closeSaveChangesDialog();
916
+ };
790
917
  usePreventUnload();
791
918
  return /* @__PURE__ */ React7.createElement(ThemeProvider, null, /* @__PURE__ */ React7.createElement(ErrorBoundary, { fallback: /* @__PURE__ */ React7.createElement(ErrorBoundaryFallback, null) }, /* @__PURE__ */ React7.createElement(Panel, null, /* @__PURE__ */ React7.createElement(PanelHeader, null, /* @__PURE__ */ React7.createElement(Stack2, { p: 1, pl: 2, width: "100%", direction: "row", alignItems: "center" }, /* @__PURE__ */ React7.createElement(PanelHeaderTitle, { sx: { display: "flex", alignItems: "center", gap: 0.5 } }, /* @__PURE__ */ React7.createElement(FlippedColorSwatchIcon, { fontSize: "inherit" }), __5("Class Manager", "elementor")), /* @__PURE__ */ React7.createElement(
792
919
  CloseButton,
@@ -813,13 +940,15 @@ function ClassManagerPanel() {
813
940
  loading: isPublishing
814
941
  },
815
942
  __5("Save changes", "elementor")
816
- )))), /* @__PURE__ */ React7.createElement(ClassManagerIntroduction, null), isSaveChangesDialogOpen && /* @__PURE__ */ React7.createElement(SaveChangesDialog, null, /* @__PURE__ */ React7.createElement(SaveChangesDialog.Title, null, __5("You have unsaved changes", "elementor")), /* @__PURE__ */ React7.createElement(SaveChangesDialog.Content, null, /* @__PURE__ */ React7.createElement(SaveChangesDialog.ContentText, null, __5("You have unsaved changes in the Class Manager.", "elementor")), /* @__PURE__ */ React7.createElement(SaveChangesDialog.ContentText, null, __5("To avoid losing your updates, save your changes before leaving.", "elementor"))), /* @__PURE__ */ React7.createElement(
943
+ )))), /* @__PURE__ */ React7.createElement(ClassManagerIntroduction, null), isSaveChangesDialogOpen && /* @__PURE__ */ React7.createElement(SaveChangesDialog, null, /* @__PURE__ */ React7.createElement(DialogHeader, { onClose: closeSaveChangesDialog, logo: false }, /* @__PURE__ */ React7.createElement(SaveChangesDialog.Title, null, __5("You have unsaved changes", "elementor"))), /* @__PURE__ */ React7.createElement(SaveChangesDialog.Content, null, /* @__PURE__ */ React7.createElement(SaveChangesDialog.ContentText, null, __5("You have unsaved changes in the Class Manager.", "elementor")), /* @__PURE__ */ React7.createElement(SaveChangesDialog.ContentText, null, __5("To avoid losing your updates, save your changes before leaving.", "elementor"))), /* @__PURE__ */ React7.createElement(
817
944
  SaveChangesDialog.Actions,
818
945
  {
819
946
  actions: {
820
- cancel: {
821
- label: __5("Cancel", "elementor"),
822
- action: closeSaveChangesDialog
947
+ discard: {
948
+ label: __5("Discard", "elementor"),
949
+ action: () => {
950
+ resetAndClosePanel();
951
+ }
823
952
  },
824
953
  confirm: {
825
954
  label: __5("Save & Continue", "elementor"),
@@ -837,7 +966,7 @@ var CloseButton = ({ onClose, ...props }) => /* @__PURE__ */ React7.createElemen
837
966
  var ErrorBoundaryFallback = () => /* @__PURE__ */ React7.createElement(Box4, { role: "alert", sx: { minHeight: "100%", p: 2 } }, /* @__PURE__ */ React7.createElement(Alert, { severity: "error", sx: { mb: 2, maxWidth: 400, textAlign: "center" } }, /* @__PURE__ */ React7.createElement("strong", null, __5("Something went wrong", "elementor"))));
838
967
  var usePreventUnload = () => {
839
968
  const isDirty2 = useDirtyState();
840
- useEffect(() => {
969
+ useEffect2(() => {
841
970
  const handleBeforeUnload = (event) => {
842
971
  if (isDirty2) {
843
972
  event.preventDefault();
@@ -904,16 +1033,16 @@ var ClassManagerButton = () => {
904
1033
  };
905
1034
 
906
1035
  // src/components/populate-store.tsx
907
- import { useEffect as useEffect2 } from "react";
1036
+ import { useEffect as useEffect3 } from "react";
908
1037
  import { __useDispatch as useDispatch2 } from "@elementor/store";
909
1038
  function PopulateStore() {
910
- const dispatch4 = useDispatch2();
911
- useEffect2(() => {
1039
+ const dispatch5 = useDispatch2();
1040
+ useEffect3(() => {
912
1041
  Promise.all([apiClient.all("preview"), apiClient.all("frontend")]).then(
913
1042
  ([previewRes, frontendRes]) => {
914
1043
  const { data: previewData } = previewRes;
915
1044
  const { data: frontendData } = frontendRes;
916
- dispatch4(
1045
+ dispatch5(
917
1046
  slice.actions.load({
918
1047
  preview: {
919
1048
  items: previewData.data,
@@ -927,7 +1056,7 @@ function PopulateStore() {
927
1056
  );
928
1057
  }
929
1058
  );
930
- }, [dispatch4]);
1059
+ }, [dispatch5]);
931
1060
  return null;
932
1061
  }
933
1062
 
@@ -972,6 +1101,10 @@ function init() {
972
1101
  id: "global-classes-manager-button",
973
1102
  component: ClassManagerButton
974
1103
  });
1104
+ registerStyleProviderToColors(GLOBAL_CLASSES_PROVIDER_KEY, {
1105
+ name: "global",
1106
+ getThemeColor: (theme) => theme.palette.global.dark
1107
+ });
975
1108
  listenTo(v1ReadyEvent(), () => {
976
1109
  syncWithDocumentSave();
977
1110
  });