@elementor/editor-global-classes 0.4.0 → 0.5.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.js CHANGED
@@ -26,31 +26,35 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  var import_editor = require("@elementor/editor");
27
27
  var import_editor_editing_panel = require("@elementor/editor-editing-panel");
28
28
  var import_editor_panels2 = require("@elementor/editor-panels");
29
- var import_editor_styles_repository = require("@elementor/editor-styles-repository");
30
- var import_store7 = require("@elementor/store");
29
+ var import_editor_styles_repository2 = require("@elementor/editor-styles-repository");
30
+ var import_editor_v1_adapters2 = require("@elementor/editor-v1-adapters");
31
+ var import_store9 = require("@elementor/store");
31
32
 
32
33
  // src/components/class-manager/class-manager-button.tsx
33
- var React3 = __toESM(require("react"));
34
- var import_icons2 = require("@elementor/icons");
35
- var import_ui3 = require("@elementor/ui");
36
- var import_i18n2 = require("@wordpress/i18n");
34
+ var React5 = __toESM(require("react"));
35
+ var import_icons5 = require("@elementor/icons");
36
+ var import_ui5 = require("@elementor/ui");
37
+ var import_i18n5 = require("@wordpress/i18n");
37
38
 
38
39
  // src/components/class-manager/class-manager-panel.tsx
39
- var React2 = __toESM(require("react"));
40
+ var React4 = __toESM(require("react"));
40
41
  var import_editor_panels = require("@elementor/editor-panels");
41
- var import_icons = require("@elementor/icons");
42
- var import_ui2 = require("@elementor/ui");
43
- var import_i18n = require("@wordpress/i18n");
42
+ var import_icons4 = require("@elementor/icons");
43
+ var import_ui4 = require("@elementor/ui");
44
+ var import_i18n4 = require("@wordpress/i18n");
44
45
 
45
46
  // src/components/class-manager/global-classes-list.tsx
46
- var React = __toESM(require("react"));
47
+ var React3 = __toESM(require("react"));
48
+ var import_editor_styles_repository = require("@elementor/editor-styles-repository");
47
49
  var import_editor_ui = require("@elementor/editor-ui");
48
- var import_ui = require("@elementor/ui");
50
+ var import_icons3 = require("@elementor/icons");
51
+ var import_ui3 = require("@elementor/ui");
52
+ var import_i18n3 = require("@wordpress/i18n");
49
53
 
50
- // src/store.ts
51
- var import_editor_props = require("@elementor/editor-props");
52
- var import_editor_styles = require("@elementor/editor-styles");
53
- var import_store = require("@elementor/store");
54
+ // src/global-classes-styles-provider.ts
55
+ var import_editor_styles2 = require("@elementor/editor-styles");
56
+ var import_store2 = require("@elementor/store");
57
+ var import_i18n = require("@wordpress/i18n");
54
58
 
55
59
  // src/errors.ts
56
60
  var import_utils = require("@elementor/utils");
@@ -58,11 +62,19 @@ var GlobalClassNotFoundError = (0, import_utils.createError)({
58
62
  code: "global_class_not_found",
59
63
  message: "Global class not found."
60
64
  });
65
+ var GlobalClassLabelAlreadyExistsError = (0, import_utils.createError)({
66
+ code: "global_class_label_already_exists",
67
+ message: "Class with this name already exists."
68
+ });
61
69
 
62
70
  // src/store.ts
71
+ var import_editor_props = require("@elementor/editor-props");
72
+ var import_editor_styles = require("@elementor/editor-styles");
73
+ var import_store = require("@elementor/store");
63
74
  var initialState = {
64
75
  items: {},
65
- order: []
76
+ order: [],
77
+ isDirty: false
66
78
  };
67
79
  var SLICE_NAME = "globalClasses";
68
80
  var slice = (0, import_store.__createSlice)({
@@ -72,14 +84,29 @@ var slice = (0, import_store.__createSlice)({
72
84
  init(state, { payload }) {
73
85
  state.items = payload.items;
74
86
  state.order = payload.order;
87
+ state.isDirty = false;
75
88
  },
76
89
  add(state, { payload }) {
77
- state.items[payload.style.id] = payload.style;
78
- state.order = payload.order;
90
+ state.items[payload.id] = payload;
91
+ state.order.push(payload.id);
92
+ state.isDirty = true;
93
+ },
94
+ delete(state, { payload }) {
95
+ state.items = Object.fromEntries(Object.entries(state.items).filter(([id]) => id !== payload));
96
+ state.order = state.order.filter((id) => id !== payload);
97
+ state.isDirty = true;
98
+ },
99
+ setOrder(state, { payload }) {
100
+ state.order = payload;
79
101
  },
80
102
  update(state, { payload }) {
81
- state.items[payload.style.id] = payload.style;
82
- state.order = payload.order;
103
+ const style = state.items[payload.style.id];
104
+ const mergedData = {
105
+ ...style,
106
+ ...payload.style
107
+ };
108
+ state.items[payload.style.id] = mergedData;
109
+ state.isDirty = true;
83
110
  },
84
111
  updateProps(state, {
85
112
  payload
@@ -94,73 +121,396 @@ var slice = (0, import_store.__createSlice)({
94
121
  } else {
95
122
  style.variants.push({ meta: payload.meta, props: payload.props });
96
123
  }
124
+ state.isDirty = true;
125
+ },
126
+ setPristine(state) {
127
+ state.isDirty = false;
97
128
  }
98
129
  }
99
130
  });
100
- var selectItems = (state) => state[SLICE_NAME].items;
101
131
  var selectOrder = (state) => state[SLICE_NAME].order;
132
+ var selectGlobalClasses = (state) => state[SLICE_NAME].items;
102
133
  var selectOrderedGlobalClasses = (0, import_store.__createSelector)(
103
- selectItems,
134
+ selectGlobalClasses,
104
135
  selectOrder,
105
136
  (items, order) => order.map((id) => items[id])
106
137
  );
107
138
  var selectClass = (state, id) => state[SLICE_NAME].items[id] ?? null;
139
+ var selectIsDirty = (state) => state.globalClasses.isDirty;
108
140
  var useOrderedGlobalClasses = () => {
109
141
  const items = (0, import_store.__useSelector)(selectOrderedGlobalClasses);
110
142
  return items;
111
143
  };
144
+ var useGlobalClassesOrder = () => (0, import_store.__useSelector)(selectOrder);
145
+
146
+ // src/global-classes-styles-provider.ts
147
+ var globalClassesStylesProvider = {
148
+ key: "global-classes",
149
+ priority: 30,
150
+ actions: {
151
+ get: () => selectOrderedGlobalClasses((0, import_store2.__getState)()),
152
+ getById: (id) => selectClass((0, import_store2.__getState)(), id),
153
+ create: (label) => {
154
+ const classes = selectGlobalClasses((0, import_store2.__getState)());
155
+ const existingLabels = Object.values(classes).map((style) => style.label);
156
+ if (existingLabels.includes(label)) {
157
+ throw new GlobalClassLabelAlreadyExistsError({ context: { label } });
158
+ }
159
+ const existingIds = Object.keys(classes);
160
+ const id = (0, import_editor_styles2.generateId)("g-", existingIds);
161
+ (0, import_store2.__dispatch)(
162
+ slice.actions.add({
163
+ id,
164
+ type: "class",
165
+ label,
166
+ variants: []
167
+ })
168
+ );
169
+ return id;
170
+ },
171
+ update: (payload) => {
172
+ (0, import_store2.__dispatch)(
173
+ slice.actions.update({
174
+ style: payload
175
+ })
176
+ );
177
+ },
178
+ delete: (id) => {
179
+ (0, import_store2.__dispatch)(slice.actions.delete(id));
180
+ },
181
+ setOrder: (order) => {
182
+ (0, import_store2.__dispatch)(slice.actions.setOrder(order));
183
+ },
184
+ updateProps: (args) => {
185
+ (0, import_store2.__dispatch)(
186
+ slice.actions.updateProps({
187
+ id: args.id,
188
+ meta: args.meta,
189
+ props: args.props
190
+ })
191
+ );
192
+ }
193
+ },
194
+ subscribe: (cb) => (0, import_store2.__subscribeWithSelector)((state) => state.globalClasses, cb),
195
+ labels: {
196
+ singular: (0, import_i18n.__)("Global class", "elementor"),
197
+ plural: (0, import_i18n.__)("Global CSS Classes", "elementor")
198
+ }
199
+ };
200
+
201
+ // src/components/class-manager/delete-confirmation-dialog.tsx
202
+ var React = __toESM(require("react"));
203
+ var import_react = require("react");
204
+ var import_icons = require("@elementor/icons");
205
+ var import_ui = require("@elementor/ui");
206
+ var import_i18n2 = require("@wordpress/i18n");
207
+ var context = (0, import_react.createContext)(null);
208
+ var DeleteConfirmationProvider = ({ children }) => {
209
+ const [dialogProps, setDialogProps] = (0, import_react.useState)(null);
210
+ const openDialog = (props) => {
211
+ setDialogProps(props);
212
+ };
213
+ const closeDialog = () => {
214
+ setDialogProps(null);
215
+ };
216
+ return /* @__PURE__ */ React.createElement(context.Provider, { value: { openDialog, closeDialog, dialogProps } }, children, !!dialogProps && /* @__PURE__ */ React.createElement(DeleteConfirmationDialog, { ...dialogProps }));
217
+ };
218
+ var TITLE_ID = "delete-class-dialog";
219
+ var DeleteConfirmationDialog = ({ label, id }) => {
220
+ const { closeDialog } = useDeleteConfirmation();
221
+ const onConfirm = () => {
222
+ globalClassesStylesProvider.actions.delete(id);
223
+ closeDialog();
224
+ };
225
+ return /* @__PURE__ */ React.createElement(import_ui.Dialog, { open: true, onClose: closeDialog, "aria-labelledby": TITLE_ID, maxWidth: "xs" }, /* @__PURE__ */ React.createElement(import_ui.DialogTitle, { id: TITLE_ID, display: "flex", alignItems: "center", gap: 1, sx: { lineHeight: 1 } }, /* @__PURE__ */ React.createElement(import_icons.AlertOctagonFilledIcon, { color: "error" }), (0, import_i18n2.__)("Delete global class", "elementor")), /* @__PURE__ */ React.createElement(import_ui.DialogContent, null, /* @__PURE__ */ React.createElement(import_ui.DialogContentText, { variant: "body2", color: "textPrimary" }, (0, import_i18n2.__)("Deleting", "elementor"), /* @__PURE__ */ React.createElement(import_ui.Typography, { variant: "subtitle2", component: "span" }, "\xA0", label, "\xA0"), (0, import_i18n2.__)(
226
+ "will permanently remove it from your project and may affect the design across all elements using it. This action cannot be undone.",
227
+ "elementor"
228
+ ))), /* @__PURE__ */ React.createElement(import_ui.DialogActions, null, /* @__PURE__ */ React.createElement(import_ui.Button, { color: "secondary", onClick: closeDialog }, (0, import_i18n2.__)("Cancel", "elementor")), /* @__PURE__ */ React.createElement(import_ui.Button, { variant: "contained", color: "error", onClick: onConfirm }, (0, import_i18n2.__)("Delete", "elementor"))));
229
+ };
230
+ var useDeleteConfirmation = () => {
231
+ const contextValue = (0, import_react.useContext)(context);
232
+ if (!contextValue) {
233
+ throw new Error("useDeleteConfirmation must be used within a DeleteConfirmationProvider");
234
+ }
235
+ return contextValue;
236
+ };
237
+
238
+ // src/components/class-manager/sortable.tsx
239
+ var React2 = __toESM(require("react"));
240
+ var import_icons2 = require("@elementor/icons");
241
+ var import_ui2 = require("@elementor/ui");
242
+ var SortableProvider = (props) => /* @__PURE__ */ React2.createElement(import_ui2.UnstableSortableProvider, { restrictAxis: true, variant: "static", dragPlaceholderStyle: { opacity: "1" }, ...props });
243
+ var SortableTrigger = (props) => /* @__PURE__ */ React2.createElement("div", { ...props, role: "button", className: "class-item-sortable-trigger" }, /* @__PURE__ */ React2.createElement(import_icons2.GripVerticalIcon, { fontSize: "tiny" }));
244
+ var SortableItem = ({ children, id }) => {
245
+ return /* @__PURE__ */ React2.createElement(
246
+ import_ui2.UnstableSortableItem,
247
+ {
248
+ id,
249
+ render: ({
250
+ itemProps,
251
+ isDragged,
252
+ triggerProps,
253
+ itemStyle,
254
+ triggerStyle,
255
+ dropIndicationStyle,
256
+ showDropIndication
257
+ }) => {
258
+ return /* @__PURE__ */ React2.createElement(StyledSortableItem, { ...itemProps, elevation: 0, sx: itemStyle, role: "listitem" }, /* @__PURE__ */ React2.createElement(SortableTrigger, { ...triggerProps, style: triggerStyle }), children({
259
+ itemProps,
260
+ isDragged,
261
+ triggerProps,
262
+ itemStyle,
263
+ triggerStyle,
264
+ dropIndicationStyle,
265
+ showDropIndication
266
+ }));
267
+ }
268
+ }
269
+ );
270
+ };
271
+ var StyledSortableItem = (0, import_ui2.styled)(import_ui2.Paper)`
272
+ position: relative;
273
+
274
+ &:hover {
275
+ & .class-item-sortable-trigger {
276
+ visibility: visible;
277
+ }
278
+ }
279
+
280
+ & .class-item-sortable-trigger {
281
+ visibility: hidden;
282
+ position: absolute;
283
+ left: 0;
284
+ top: 50%;
285
+ transform: translate( -75%, -50% );
286
+ }
287
+ `;
288
+ var SortableItemIndicator = (0, import_ui2.styled)(import_ui2.Box)`
289
+ width: 100%;
290
+ height: 3px;
291
+ border-radius: ${({ theme }) => theme.spacing(0.5)};
292
+ background-color: ${({ theme }) => theme.palette.text.primary};
293
+ `;
112
294
 
113
295
  // src/components/class-manager/global-classes-list.tsx
114
296
  var GlobalClassesList = () => {
115
297
  const cssClasses = useOrderedGlobalClasses();
116
- return /* @__PURE__ */ React.createElement(import_ui.Stack, null, /* @__PURE__ */ React.createElement(import_ui.List, { role: "list" }, cssClasses?.map(({ id, label }) => {
117
- return /* @__PURE__ */ React.createElement(import_ui.Stack, { key: id, direction: "row", alignItems: "center", gap: 1, role: "listitem" }, /* @__PURE__ */ React.createElement(import_ui.ListItemButton, { sx: { borderRadius: 1 } }, /* @__PURE__ */ React.createElement(import_editor_ui.EllipsisWithTooltip, { title: label, as: import_ui.Typography, variant: "caption" })));
118
- })));
298
+ const [classesOrder, reorderClasses] = useClassesOrder();
299
+ if (!cssClasses?.length) {
300
+ return /* @__PURE__ */ React3.createElement(EmptyState, null);
301
+ }
302
+ return /* @__PURE__ */ React3.createElement(DeleteConfirmationProvider, null, /* @__PURE__ */ React3.createElement(import_ui3.List, { sx: { display: "flex", flexDirection: "column", gap: 0.5 } }, /* @__PURE__ */ React3.createElement(SortableProvider, { value: classesOrder, onChange: reorderClasses }, cssClasses?.map(({ id, label }) => {
303
+ const renameClass = (newLabel) => {
304
+ globalClassesStylesProvider.actions.update({ label: newLabel, id });
305
+ };
306
+ return /* @__PURE__ */ React3.createElement(SortableItem, { key: id, id }, ({ isDragged, showDropIndication, dropIndicationStyle }) => /* @__PURE__ */ React3.createElement(
307
+ ClassItem,
308
+ {
309
+ id,
310
+ label,
311
+ renameClass,
312
+ selected: isDragged
313
+ },
314
+ showDropIndication && /* @__PURE__ */ React3.createElement(SortableItemIndicator, { style: dropIndicationStyle })
315
+ ));
316
+ }))));
317
+ };
318
+ var useClassesOrder = () => {
319
+ const order = useGlobalClassesOrder();
320
+ const reorder = (newIds) => {
321
+ globalClassesStylesProvider.actions.setOrder(newIds);
322
+ };
323
+ return [order, reorder];
324
+ };
325
+ var ClassItem = ({
326
+ id,
327
+ label,
328
+ renameClass,
329
+ selected,
330
+ children
331
+ }) => {
332
+ const {
333
+ ref: editableRef,
334
+ openEditMode,
335
+ isEditing,
336
+ error,
337
+ getProps: getEditableProps
338
+ } = (0, import_editor_ui.useEditable)({
339
+ value: label,
340
+ onSubmit: renameClass,
341
+ validation: validateLabel
342
+ });
343
+ const { openDialog } = useDeleteConfirmation();
344
+ const popupState = (0, import_ui3.usePopupState)({
345
+ variant: "popover",
346
+ disableAutoFocus: true
347
+ });
348
+ return /* @__PURE__ */ React3.createElement(import_ui3.Stack, { direction: "row", alignItems: "center", gap: 1, flexGrow: 1, flexShrink: 0 }, /* @__PURE__ */ React3.createElement(
349
+ StyledListItem,
350
+ {
351
+ component: "div",
352
+ disablePadding: true,
353
+ disableGutters: true,
354
+ secondaryAction: /* @__PURE__ */ React3.createElement(
355
+ import_ui3.Tooltip,
356
+ {
357
+ placement: "top",
358
+ className: "class-item-more-actions",
359
+ title: (0, import_i18n3.__)("More actions", "elementor")
360
+ },
361
+ /* @__PURE__ */ React3.createElement(import_ui3.IconButton, { size: "tiny", ...(0, import_ui3.bindTrigger)(popupState), "aria-label": "More actions" }, /* @__PURE__ */ React3.createElement(import_icons3.DotsVerticalIcon, { fontSize: "tiny" }))
362
+ )
363
+ },
364
+ /* @__PURE__ */ React3.createElement(
365
+ import_ui3.ListItemButton,
366
+ {
367
+ dense: true,
368
+ disableGutters: true,
369
+ shape: "rounded",
370
+ onDoubleClick: openEditMode,
371
+ selected: selected || popupState.isOpen,
372
+ focusVisibleClassName: "visible-class-item",
373
+ sx: {
374
+ minHeight: "36px",
375
+ display: "flex",
376
+ "&.visible-class-item": {
377
+ boxShadow: "none !important"
378
+ }
379
+ }
380
+ },
381
+ /* @__PURE__ */ React3.createElement(Indicator, { isActive: isEditing, isError: !!error }, isEditing ? /* @__PURE__ */ React3.createElement(
382
+ import_editor_ui.EditableField,
383
+ {
384
+ ref: editableRef,
385
+ error,
386
+ as: import_ui3.Typography,
387
+ variant: "caption",
388
+ ...getEditableProps()
389
+ }
390
+ ) : /* @__PURE__ */ React3.createElement(import_editor_ui.EllipsisWithTooltip, { title: label, as: import_ui3.Typography, variant: "caption" }))
391
+ ),
392
+ children,
393
+ /* @__PURE__ */ React3.createElement(
394
+ import_ui3.Menu,
395
+ {
396
+ ...(0, import_ui3.bindMenu)(popupState),
397
+ anchorOrigin: {
398
+ vertical: "bottom",
399
+ horizontal: "right"
400
+ },
401
+ transformOrigin: {
402
+ vertical: "top",
403
+ horizontal: "right"
404
+ }
405
+ },
406
+ /* @__PURE__ */ React3.createElement(
407
+ import_ui3.MenuItem,
408
+ {
409
+ sx: { minWidth: "160px" },
410
+ onClick: () => {
411
+ popupState.close();
412
+ openEditMode();
413
+ }
414
+ },
415
+ /* @__PURE__ */ React3.createElement(import_ui3.ListItemText, { primary: (0, import_i18n3.__)("Rename", "elementor") })
416
+ ),
417
+ /* @__PURE__ */ React3.createElement(
418
+ import_ui3.MenuItem,
419
+ {
420
+ onClick: () => {
421
+ popupState.close();
422
+ openDialog({ id, label });
423
+ }
424
+ },
425
+ /* @__PURE__ */ React3.createElement(import_ui3.ListItemText, { primary: (0, import_i18n3.__)("Delete", "elementor"), sx: { color: "error.light" } })
426
+ )
427
+ )
428
+ ));
429
+ };
430
+ var StyledListItem = (0, import_ui3.styled)(import_ui3.ListItem)`
431
+ .class-item-more-actions {
432
+ visibility: hidden;
433
+ }
434
+ &:hover {
435
+ .class-item-more-actions {
436
+ visibility: visible;
437
+ }
438
+ }
439
+ `;
440
+ var EmptyState = () => /* @__PURE__ */ React3.createElement(import_ui3.Stack, { alignItems: "center", gap: 3, pt: 4, px: 0.5 }, /* @__PURE__ */ React3.createElement(import_icons3.PhotoIcon, { fontSize: "large" }), /* @__PURE__ */ React3.createElement(StyledHeader, { variant: "subtitle2", component: "h2", color: "text.secondary" }, (0, import_i18n3.__)("No CSS classes created yet", "elementor")), /* @__PURE__ */ React3.createElement(import_ui3.Typography, { align: "center", variant: "caption", color: "text.secondary" }, (0, import_i18n3.__)(
441
+ "CSS classes created in the editor panel will appear here. Once they are available, you can arrange their hierarchy, rename them, or delete them as needed.",
442
+ "elementor"
443
+ )));
444
+ var StyledHeader = (0, import_ui3.styled)(import_ui3.Typography)(({ theme, variant }) => ({
445
+ "&.MuiTypography-root": {
446
+ ...theme.typography[variant]
447
+ }
448
+ }));
449
+ var Indicator = (0, import_ui3.styled)(import_ui3.Box, {
450
+ shouldForwardProp: (prop) => !["isActive", "isError"].includes(prop)
451
+ })(({ theme, isActive, isError }) => ({
452
+ display: "flex",
453
+ width: "100%",
454
+ flexGrow: 1,
455
+ borderRadius: theme.spacing(0.5),
456
+ border: getIndicatorBorder({ isActive, isError, theme }),
457
+ padding: `0 ${theme.spacing(1)}`,
458
+ marginLeft: isActive ? theme.spacing(1) : 0
459
+ }));
460
+ var getIndicatorBorder = ({ isActive, isError, theme }) => {
461
+ if (isError) {
462
+ return `2px solid ${theme.palette.error.main}`;
463
+ }
464
+ if (isActive) {
465
+ return `2px solid ${theme.palette.secondary.main}`;
466
+ }
467
+ return "none";
468
+ };
469
+ var validateLabel = (newLabel) => {
470
+ if (!import_editor_styles_repository.stylesRepository.isLabelValid(newLabel)) {
471
+ return (0, import_i18n3.__)("Format is not valid", "elementor");
472
+ }
473
+ if (import_editor_styles_repository.stylesRepository.isLabelExist(newLabel)) {
474
+ return (0, import_i18n3.__)("Existing name", "elementor");
475
+ }
119
476
  };
120
477
 
121
478
  // src/components/class-manager/class-manager-panel.tsx
122
- var { panel, usePanelActions, usePanelStatus } = (0, import_editor_panels.__createPanel)({
479
+ var { panel, usePanelActions } = (0, import_editor_panels.__createPanel)({
123
480
  id: "class-manager-panel",
124
481
  component: ClassManagerPanel
125
482
  });
126
483
  function ClassManagerPanel() {
127
- return /* @__PURE__ */ React2.createElement(import_ui2.ErrorBoundary, { fallback: /* @__PURE__ */ React2.createElement(ErrorBoundaryFallback, null) }, /* @__PURE__ */ React2.createElement(import_editor_panels.Panel, null, /* @__PURE__ */ React2.createElement(import_editor_panels.PanelHeader, null, /* @__PURE__ */ React2.createElement(import_ui2.Stack, { p: 1, width: "100%", direction: "row", alignItems: "center" }, /* @__PURE__ */ React2.createElement(import_editor_panels.PanelHeaderTitle, { sx: { display: "flex", alignItems: "center", gap: 0.5 } }, /* @__PURE__ */ React2.createElement(import_icons.ColorSwatchIcon, { fontSize: "inherit", sx: { transform: "rotate(90deg)" } }), (0, import_i18n.__)("CSS Class manager")), /* @__PURE__ */ React2.createElement(CloseButton, { sx: { marginLeft: "auto" } }))), /* @__PURE__ */ React2.createElement(import_editor_panels.PanelBody, { px: 2 }, /* @__PURE__ */ React2.createElement(GlobalClassesList, null))));
484
+ return /* @__PURE__ */ React4.createElement(import_ui4.ErrorBoundary, { fallback: /* @__PURE__ */ React4.createElement(ErrorBoundaryFallback, null) }, /* @__PURE__ */ React4.createElement(import_editor_panels.Panel, null, /* @__PURE__ */ React4.createElement(import_editor_panels.PanelHeader, null, /* @__PURE__ */ React4.createElement(import_ui4.Stack, { p: 1, pl: 2, width: "100%", direction: "row", alignItems: "center" }, /* @__PURE__ */ React4.createElement(import_editor_panels.PanelHeaderTitle, { sx: { display: "flex", alignItems: "center", gap: 0.5 } }, /* @__PURE__ */ React4.createElement(import_icons4.ColorSwatchIcon, { fontSize: "inherit", sx: { transform: "rotate(90deg)" } }), (0, import_i18n4.__)("CSS Class manager")), /* @__PURE__ */ React4.createElement(CloseButton, { sx: { marginLeft: "auto" } }))), /* @__PURE__ */ React4.createElement(import_editor_panels.PanelBody, { px: 2 }, /* @__PURE__ */ React4.createElement(GlobalClassesList, null))));
128
485
  }
129
486
  var CloseButton = (props) => {
130
487
  const { close } = usePanelActions();
131
- return /* @__PURE__ */ React2.createElement(import_ui2.IconButton, { size: "small", color: "secondary", onClick: close, ...props }, /* @__PURE__ */ React2.createElement(import_icons.XIcon, { fontSize: "small" }));
488
+ return /* @__PURE__ */ React4.createElement(import_ui4.IconButton, { size: "small", color: "secondary", onClick: close, ...props }, /* @__PURE__ */ React4.createElement(import_icons4.XIcon, { fontSize: "small" }));
132
489
  };
133
- var ErrorBoundaryFallback = () => /* @__PURE__ */ React2.createElement(import_ui2.Box, { role: "alert", sx: { minHeight: "100%", p: 2 } }, /* @__PURE__ */ React2.createElement(import_ui2.Alert, { severity: "error", sx: { mb: 2, maxWidth: 400, textAlign: "center" } }, /* @__PURE__ */ React2.createElement("strong", null, (0, import_i18n.__)("Something went wrong", "elementor"))));
490
+ var ErrorBoundaryFallback = () => /* @__PURE__ */ React4.createElement(import_ui4.Box, { role: "alert", sx: { minHeight: "100%", p: 2 } }, /* @__PURE__ */ React4.createElement(import_ui4.Alert, { severity: "error", sx: { mb: 2, maxWidth: 400, textAlign: "center" } }, /* @__PURE__ */ React4.createElement("strong", null, (0, import_i18n4.__)("Something went wrong", "elementor"))));
134
491
 
135
492
  // src/components/class-manager/class-manager-button.tsx
136
493
  var ClassManagerButton = () => {
137
494
  const { open } = usePanelActions();
138
- return /* @__PURE__ */ React3.createElement(import_ui3.Tooltip, { title: (0, import_i18n2.__)("Class manager"), placement: "top" }, /* @__PURE__ */ React3.createElement(import_ui3.IconButton, { onClick: open }, /* @__PURE__ */ React3.createElement(import_icons2.ColorSwatchIcon, { fontSize: "tiny" })));
495
+ return /* @__PURE__ */ React5.createElement(import_ui5.Tooltip, { title: (0, import_i18n5.__)("Class manager"), placement: "top" }, /* @__PURE__ */ React5.createElement(import_ui5.IconButton, { onClick: open }, /* @__PURE__ */ React5.createElement(import_icons5.ColorSwatchIcon, { fontSize: "tiny" })));
139
496
  };
140
497
 
141
- // src/components/logic-hooks.tsx
142
- var import_react = require("react");
143
- var import_store3 = require("@elementor/store");
498
+ // src/components/populate-store.tsx
499
+ var import_react2 = require("react");
500
+ var import_store5 = require("@elementor/store");
144
501
 
145
502
  // src/api.ts
146
503
  var import_http = require("@elementor/http");
147
504
  var RESOURCE_URL = "/global-classes";
148
505
  var apiClient = {
149
- all: async () => {
150
- return (0, import_http.httpService)().get(RESOURCE_URL);
151
- },
152
- post: async (data) => {
153
- return (0, import_http.httpService)().post(RESOURCE_URL, data);
154
- },
155
- put: async (id, data) => {
156
- return (0, import_http.httpService)().put(`${RESOURCE_URL}/${id}`, data);
157
- }
506
+ all: () => (0, import_http.httpService)().get("elementor/v1" + RESOURCE_URL),
507
+ update: (payload) => (0, import_http.httpService)().put("elementor/v1" + RESOURCE_URL, payload)
158
508
  };
159
509
 
160
- // src/components/logic-hooks.tsx
161
- function LogicHooks() {
162
- const dispatch2 = (0, import_store3.__useDispatch)();
163
- (0, import_react.useEffect)(() => {
510
+ // src/components/populate-store.tsx
511
+ function PopulateStore() {
512
+ const dispatch2 = (0, import_store5.__useDispatch)();
513
+ (0, import_react2.useEffect)(() => {
164
514
  apiClient.all().then((res) => {
165
515
  const { data, meta } = res.data;
166
516
  dispatch2(slice.actions.init({ items: data, order: meta.order }));
@@ -169,69 +519,55 @@ function LogicHooks() {
169
519
  return null;
170
520
  }
171
521
 
172
- // src/global-classes-styles-provider.ts
173
- var import_store5 = require("@elementor/store");
174
- var import_i18n3 = require("@wordpress/i18n");
175
- var globalClassesStylesProvider = {
176
- key: "global-classes",
177
- priority: 30,
178
- actions: {
179
- get: () => selectOrderedGlobalClasses((0, import_store5.__getState)()),
180
- getById: (id) => selectClass((0, import_store5.__getState)(), id),
181
- create: async (style) => {
182
- const res = await apiClient.post(style);
183
- const { data, meta } = res.data;
184
- (0, import_store5.__dispatch)(
185
- slice.actions.add({
186
- style: data,
187
- order: meta.order
188
- })
189
- );
190
- return data;
191
- },
192
- update: async (payload) => {
193
- const style = selectClass((0, import_store5.__getState)(), payload.id);
194
- const mergedData = { ...style, ...payload };
195
- const res = await apiClient.put(payload.id, mergedData);
196
- const { data, meta } = res.data;
197
- (0, import_store5.__dispatch)(
198
- slice.actions.update({
199
- style: data,
200
- order: meta.order
201
- })
202
- );
203
- return data;
204
- },
205
- updateProps: (args) => {
206
- (0, import_store5.__dispatch)(
207
- slice.actions.updateProps({
208
- id: args.id,
209
- meta: args.meta,
210
- props: args.props
211
- })
212
- );
522
+ // src/sync-with-document-save.ts
523
+ var import_editor_v1_adapters = require("@elementor/editor-v1-adapters");
524
+ var import_store7 = require("@elementor/store");
525
+ function syncWithDocumentSave() {
526
+ const unsubscribe = syncDirtyState();
527
+ bindSaveAction();
528
+ return unsubscribe;
529
+ }
530
+ function syncDirtyState() {
531
+ return (0, import_store7.__subscribeWithSelector)(selectIsDirty, () => {
532
+ if (!isDirty()) {
533
+ return;
213
534
  }
214
- },
215
- subscribe: (cb) => (0, import_store5.__subscribeWithSelector)((state) => state.globalClasses, cb),
216
- labels: {
217
- singular: (0, import_i18n3.__)("Global CSS Class", "elementor"),
218
- plural: (0, import_i18n3.__)("Global CSS Classes", "elementor")
219
- }
220
- };
535
+ (0, import_editor_v1_adapters.__privateRunCommandSync)("document/save/set-is-modified", { status: true }, { internal: true });
536
+ });
537
+ }
538
+ function bindSaveAction() {
539
+ (0, import_editor_v1_adapters.registerDataHook)("after", "document/save/save", async () => {
540
+ if (!isDirty()) {
541
+ return;
542
+ }
543
+ const state = (0, import_store7.__getState)().globalClasses;
544
+ await apiClient.update({
545
+ items: state.items,
546
+ order: state.order
547
+ });
548
+ (0, import_store7.__dispatch)(slice.actions.setPristine());
549
+ });
550
+ }
551
+ function isDirty() {
552
+ return selectIsDirty((0, import_store7.__getState)());
553
+ }
221
554
 
222
555
  // src/init.ts
223
556
  function init() {
224
- (0, import_store7.__registerSlice)(slice);
557
+ (0, import_store9.__registerSlice)(slice);
225
558
  (0, import_editor_panels2.__registerPanel)(panel);
226
- import_editor_styles_repository.stylesRepository.register(globalClassesStylesProvider);
559
+ import_editor_styles_repository2.stylesRepository.register(globalClassesStylesProvider);
227
560
  (0, import_editor.injectIntoLogic)({
228
- id: "global-classes-hooks",
229
- component: LogicHooks
561
+ id: "global-classes-populate-store",
562
+ component: PopulateStore
230
563
  });
231
564
  (0, import_editor_editing_panel.injectIntoClassSelectorActions)({
232
- id: "global-classes",
565
+ id: "global-classes-manager-button",
233
566
  component: ClassManagerButton
234
567
  });
568
+ (0, import_editor_v1_adapters2.__privateListenTo)((0, import_editor_v1_adapters2.v1ReadyEvent)(), () => {
569
+ syncWithDocumentSave();
570
+ });
235
571
  }
236
572
 
237
573
  // src/index.ts