@elementor/editor-global-classes 0.9.1 → 0.11.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
@@ -7,13 +7,17 @@ import { __privateListenTo as listenTo, v1ReadyEvent } from "@elementor/editor-v
7
7
  import { __registerSlice as registerSlice } from "@elementor/store";
8
8
 
9
9
  // src/components/class-manager/class-manager-button.tsx
10
- import * as React7 from "react";
11
- import { ColorSwatchIcon as ColorSwatchIcon2 } from "@elementor/icons";
10
+ import * as React8 from "react";
11
+ import {
12
+ __useActiveDocument as useActiveDocument,
13
+ __useActiveDocumentActions as useActiveDocumentActions
14
+ } from "@elementor/editor-documents";
12
15
  import { IconButton as IconButton3, Tooltip as Tooltip2 } from "@elementor/ui";
13
16
  import { __ as __6 } from "@wordpress/i18n";
14
17
 
15
18
  // src/components/class-manager/class-manager-panel.tsx
16
- import * as React6 from "react";
19
+ import * as React7 from "react";
20
+ import { useEffect } from "react";
17
21
  import {
18
22
  __createPanel as createPanel,
19
23
  Panel,
@@ -22,7 +26,8 @@ import {
22
26
  PanelHeader,
23
27
  PanelHeaderTitle
24
28
  } from "@elementor/editor-panels";
25
- import { ColorSwatchIcon, XIcon } from "@elementor/icons";
29
+ import { changeEditMode } from "@elementor/editor-v1-adapters";
30
+ import { XIcon } from "@elementor/icons";
26
31
  import { Alert, Box as Box4, Button as Button3, ErrorBoundary, IconButton as IconButton2, Stack as Stack3 } from "@elementor/ui";
27
32
  import { __ as __5 } from "@wordpress/i18n";
28
33
 
@@ -72,8 +77,8 @@ var slice = createSlice({
72
77
  state.isDirty = true;
73
78
  },
74
79
  delete(state, { payload }) {
75
- state.items = Object.fromEntries(Object.entries(state.items).filter(([id]) => id !== payload));
76
- state.order = state.order.filter((id) => id !== payload);
80
+ state.items = Object.fromEntries(Object.entries(state.items).filter(([id2]) => id2 !== payload));
81
+ state.order = state.order.filter((id2) => id2 !== payload);
77
82
  state.isDirty = true;
78
83
  },
79
84
  setOrder(state, { payload }) {
@@ -114,9 +119,9 @@ var selectGlobalClasses = (state) => state[SLICE_NAME].items;
114
119
  var selectOrderedClasses = createSelector(
115
120
  selectGlobalClasses,
116
121
  selectOrder,
117
- (items, order) => order.map((id) => items[id])
122
+ (items, order) => order.map((id2) => items[id2])
118
123
  );
119
- var selectClass = (state, id) => state[SLICE_NAME].items[id] ?? null;
124
+ var selectClass = (state, id2) => state[SLICE_NAME].items[id2] ?? null;
120
125
  var selectIsDirty = (state) => state.globalClasses.isDirty;
121
126
 
122
127
  // src/hooks/use-dirty-state.ts
@@ -158,7 +163,7 @@ import { useSuppressedMessage } from "@elementor/editor-current-user";
158
163
  import { IntroductionModal } from "@elementor/editor-ui";
159
164
  import { Box, Image, Stack, Typography } from "@elementor/ui";
160
165
  import { __ } from "@wordpress/i18n";
161
- var MESSAGE_KEY = "global-class-manager-4";
166
+ var MESSAGE_KEY = "global-class-manager";
162
167
  var ClassManagerIntroduction = () => {
163
168
  const [isMessageSuppressed, suppressMessage] = useSuppressedMessage(MESSAGE_KEY);
164
169
  const [shouldShowIntroduction, setShouldShowIntroduction] = useState(!isMessageSuppressed);
@@ -187,11 +192,16 @@ var IntroductionContent = () => {
187
192
  ))));
188
193
  };
189
194
 
195
+ // src/components/class-manager/flipped-color-swatch-icon.tsx
196
+ import * as React2 from "react";
197
+ import { ColorSwatchIcon } from "@elementor/icons";
198
+ var FlippedColorSwatchIcon = ({ sx, ...props }) => /* @__PURE__ */ React2.createElement(ColorSwatchIcon, { sx: { transform: "rotate(90deg)", ...sx }, ...props });
199
+
190
200
  // src/components/class-manager/global-classes-list.tsx
191
- import * as React4 from "react";
201
+ import * as React5 from "react";
192
202
  import { stylesRepository } from "@elementor/editor-styles-repository";
193
203
  import { EditableField, EllipsisWithTooltip, useEditable } from "@elementor/editor-ui";
194
- import { DotsVerticalIcon, PhotoIcon } from "@elementor/icons";
204
+ import { DotsVerticalIcon } from "@elementor/icons";
195
205
  import {
196
206
  bindMenu,
197
207
  bindTrigger,
@@ -224,7 +234,7 @@ var globalClassesStylesProvider = {
224
234
  priority: 30,
225
235
  actions: {
226
236
  get: () => selectOrderedClasses(getState2()),
227
- getById: (id) => selectClass(getState2(), id),
237
+ getById: (id2) => selectClass(getState2(), id2),
228
238
  create: (label) => {
229
239
  const classes = selectGlobalClasses(getState2());
230
240
  const existingLabels = Object.values(classes).map((style) => style.label);
@@ -232,16 +242,16 @@ var globalClassesStylesProvider = {
232
242
  throw new GlobalClassLabelAlreadyExistsError({ context: { label } });
233
243
  }
234
244
  const existingIds = Object.keys(classes);
235
- const id = generateId("g-", existingIds);
245
+ const id2 = generateId("g-", existingIds);
236
246
  dispatch2(
237
247
  slice.actions.add({
238
- id,
248
+ id: id2,
239
249
  type: "class",
240
250
  label,
241
251
  variants: []
242
252
  })
243
253
  );
244
- return id;
254
+ return id2;
245
255
  },
246
256
  update: (payload) => {
247
257
  dispatch2(
@@ -250,8 +260,8 @@ var globalClassesStylesProvider = {
250
260
  })
251
261
  );
252
262
  },
253
- delete: (id) => {
254
- dispatch2(slice.actions.delete(id));
263
+ delete: (id2) => {
264
+ dispatch2(slice.actions.delete(id2));
255
265
  },
256
266
  setOrder: (order) => {
257
267
  dispatch2(slice.actions.setOrder(order));
@@ -269,7 +279,7 @@ var globalClassesStylesProvider = {
269
279
  subscribe: (cb) => subscribeWithSelector((state) => state.globalClasses, cb),
270
280
  labels: {
271
281
  singular: __2("Global class", "elementor"),
272
- plural: __2("Global CSS Classes", "elementor")
282
+ plural: __2("Global CSS classes", "elementor")
273
283
  }
274
284
  };
275
285
 
@@ -286,7 +296,7 @@ var useOrderedClasses = () => {
286
296
  };
287
297
 
288
298
  // src/components/class-manager/delete-confirmation-dialog.tsx
289
- import * as React2 from "react";
299
+ import * as React3 from "react";
290
300
  import { createContext, useContext, useState as useState2 } from "react";
291
301
  import { AlertOctagonFilledIcon } from "@elementor/icons";
292
302
  import {
@@ -308,19 +318,19 @@ var DeleteConfirmationProvider = ({ children }) => {
308
318
  const closeDialog = () => {
309
319
  setDialogProps(null);
310
320
  };
311
- return /* @__PURE__ */ React2.createElement(context.Provider, { value: { openDialog, closeDialog, dialogProps } }, children, !!dialogProps && /* @__PURE__ */ React2.createElement(DeleteConfirmationDialog, { ...dialogProps }));
321
+ return /* @__PURE__ */ React3.createElement(context.Provider, { value: { openDialog, closeDialog, dialogProps } }, children, !!dialogProps && /* @__PURE__ */ React3.createElement(DeleteConfirmationDialog, { ...dialogProps }));
312
322
  };
313
323
  var TITLE_ID = "delete-class-dialog";
314
- var DeleteConfirmationDialog = ({ label, id }) => {
324
+ var DeleteConfirmationDialog = ({ label, id: id2 }) => {
315
325
  const { closeDialog } = useDeleteConfirmation();
316
326
  const onConfirm = () => {
317
- globalClassesStylesProvider.actions.delete(id);
327
+ globalClassesStylesProvider.actions.delete(id2);
318
328
  closeDialog();
319
329
  };
320
- return /* @__PURE__ */ React2.createElement(Dialog, { open: true, onClose: closeDialog, "aria-labelledby": TITLE_ID, maxWidth: "xs" }, /* @__PURE__ */ React2.createElement(DialogTitle, { id: TITLE_ID, display: "flex", alignItems: "center", gap: 1, sx: { lineHeight: 1 } }, /* @__PURE__ */ React2.createElement(AlertOctagonFilledIcon, { color: "error" }), __3("Delete global class", "elementor")), /* @__PURE__ */ React2.createElement(DialogContent, null, /* @__PURE__ */ React2.createElement(DialogContentText, { variant: "body2", color: "textPrimary" }, __3("Deleting", "elementor"), /* @__PURE__ */ React2.createElement(Typography2, { variant: "subtitle2", component: "span" }, "\xA0", label, "\xA0"), __3(
330
+ return /* @__PURE__ */ React3.createElement(Dialog, { open: true, onClose: closeDialog, "aria-labelledby": TITLE_ID, maxWidth: "xs" }, /* @__PURE__ */ React3.createElement(DialogTitle, { id: TITLE_ID, display: "flex", alignItems: "center", gap: 1, sx: { lineHeight: 1 } }, /* @__PURE__ */ React3.createElement(AlertOctagonFilledIcon, { color: "error" }), __3("Delete global class", "elementor")), /* @__PURE__ */ React3.createElement(DialogContent, null, /* @__PURE__ */ React3.createElement(DialogContentText, { variant: "body2", color: "textPrimary" }, __3("Deleting", "elementor"), /* @__PURE__ */ React3.createElement(Typography2, { variant: "subtitle2", component: "span" }, "\xA0", label, "\xA0"), __3(
321
331
  "will permanently remove it from your project and may affect the design across all elements using it. This action cannot be undone.",
322
332
  "elementor"
323
- ))), /* @__PURE__ */ React2.createElement(DialogActions, null, /* @__PURE__ */ React2.createElement(Button, { color: "secondary", onClick: closeDialog }, __3("Cancel", "elementor")), /* @__PURE__ */ React2.createElement(Button, { variant: "contained", color: "error", onClick: onConfirm }, __3("Delete", "elementor"))));
333
+ ))), /* @__PURE__ */ React3.createElement(DialogActions, null, /* @__PURE__ */ React3.createElement(Button, { color: "secondary", onClick: closeDialog }, __3("Cancel", "elementor")), /* @__PURE__ */ React3.createElement(Button, { variant: "contained", color: "error", onClick: onConfirm }, __3("Delete", "elementor"))));
324
334
  };
325
335
  var useDeleteConfirmation = () => {
326
336
  const contextValue = useContext(context);
@@ -331,7 +341,7 @@ var useDeleteConfirmation = () => {
331
341
  };
332
342
 
333
343
  // src/components/class-manager/sortable.tsx
334
- import * as React3 from "react";
344
+ import * as React4 from "react";
335
345
  import { GripVerticalIcon } from "@elementor/icons";
336
346
  import {
337
347
  Box as Box2,
@@ -340,13 +350,14 @@ import {
340
350
  UnstableSortableItem,
341
351
  UnstableSortableProvider
342
352
  } from "@elementor/ui";
343
- var SortableProvider = (props) => /* @__PURE__ */ React3.createElement(UnstableSortableProvider, { restrictAxis: true, variant: "static", dragPlaceholderStyle: { opacity: "1" }, ...props });
344
- var SortableTrigger = (props) => /* @__PURE__ */ React3.createElement("div", { ...props, role: "button", className: "class-item-sortable-trigger" }, /* @__PURE__ */ React3.createElement(GripVerticalIcon, { fontSize: "tiny" }));
345
- var SortableItem = ({ children, id }) => {
346
- return /* @__PURE__ */ React3.createElement(
353
+ var SortableProvider = (props) => /* @__PURE__ */ React4.createElement(UnstableSortableProvider, { restrictAxis: true, variant: "static", dragPlaceholderStyle: { opacity: "1" }, ...props });
354
+ var SortableTrigger = (props) => /* @__PURE__ */ React4.createElement("div", { ...props, role: "button", className: "class-item-sortable-trigger" }, /* @__PURE__ */ React4.createElement(GripVerticalIcon, { fontSize: "tiny" }));
355
+ var SortableItem = ({ children, id: id2, ...props }) => {
356
+ return /* @__PURE__ */ React4.createElement(
347
357
  UnstableSortableItem,
348
358
  {
349
- id,
359
+ ...props,
360
+ id: id2,
350
361
  render: ({
351
362
  itemProps,
352
363
  isDragged,
@@ -354,22 +365,35 @@ var SortableItem = ({ children, id }) => {
354
365
  itemStyle,
355
366
  triggerStyle,
356
367
  dropIndicationStyle,
357
- showDropIndication
368
+ showDropIndication,
369
+ isDragOverlay,
370
+ isDragPlaceholder
358
371
  }) => {
359
- return /* @__PURE__ */ React3.createElement(StyledSortableItem, { ...itemProps, elevation: 0, sx: itemStyle, role: "listitem" }, /* @__PURE__ */ React3.createElement(SortableTrigger, { ...triggerProps, style: triggerStyle }), children({
360
- itemProps,
361
- isDragged,
362
- triggerProps,
363
- itemStyle,
364
- triggerStyle,
365
- dropIndicationStyle,
366
- showDropIndication
367
- }));
372
+ return /* @__PURE__ */ React4.createElement(
373
+ StyledSortableItem,
374
+ {
375
+ ...itemProps,
376
+ sx: itemStyle,
377
+ role: "listitem",
378
+ ...isDragOverlay ? { component: Paper, elevation: 0 } : {}
379
+ },
380
+ /* @__PURE__ */ React4.createElement(SortableTrigger, { ...triggerProps, style: triggerStyle }),
381
+ children({
382
+ itemProps,
383
+ isDragged,
384
+ triggerProps,
385
+ itemStyle,
386
+ triggerStyle,
387
+ dropIndicationStyle,
388
+ showDropIndication,
389
+ isDragPlaceholder
390
+ })
391
+ );
368
392
  }
369
393
  }
370
394
  );
371
395
  };
372
- var StyledSortableItem = styled(Paper)`
396
+ var StyledSortableItem = styled(Box2)`
373
397
  position: relative;
374
398
 
375
399
  &:hover {
@@ -398,21 +422,22 @@ var GlobalClassesList = () => {
398
422
  const cssClasses = useOrderedClasses();
399
423
  const [classesOrder, reorderClasses] = useReorder();
400
424
  if (!cssClasses?.length) {
401
- return /* @__PURE__ */ React4.createElement(EmptyState, null);
425
+ return /* @__PURE__ */ React5.createElement(EmptyState, null);
402
426
  }
403
- return /* @__PURE__ */ React4.createElement(DeleteConfirmationProvider, null, /* @__PURE__ */ React4.createElement(List, { sx: { display: "flex", flexDirection: "column", gap: 0.5 } }, /* @__PURE__ */ React4.createElement(SortableProvider, { value: classesOrder, onChange: reorderClasses }, cssClasses?.map(({ id, label }) => {
427
+ 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 }) => {
404
428
  const renameClass = (newLabel) => {
405
- globalClassesStylesProvider.actions.update({ label: newLabel, id });
429
+ globalClassesStylesProvider.actions.update({ label: newLabel, id: id2 });
406
430
  };
407
- return /* @__PURE__ */ React4.createElement(SortableItem, { key: id, id }, ({ isDragged, showDropIndication, dropIndicationStyle }) => /* @__PURE__ */ React4.createElement(
431
+ return /* @__PURE__ */ React5.createElement(SortableItem, { key: id2, id: id2 }, ({ isDragged, showDropIndication, dropIndicationStyle, isDragPlaceholder }) => /* @__PURE__ */ React5.createElement(
408
432
  ClassItem,
409
433
  {
410
- id,
434
+ id: id2,
411
435
  label,
412
436
  renameClass,
413
- selected: isDragged
437
+ selected: isDragged,
438
+ disabled: isDragPlaceholder
414
439
  },
415
- showDropIndication && /* @__PURE__ */ React4.createElement(SortableItemIndicator, { style: dropIndicationStyle })
440
+ showDropIndication && /* @__PURE__ */ React5.createElement(SortableItemIndicator, { style: dropIndicationStyle })
416
441
  ));
417
442
  }))));
418
443
  };
@@ -424,11 +449,12 @@ var useReorder = () => {
424
449
  return [order, reorder];
425
450
  };
426
451
  var ClassItem = ({
427
- id,
452
+ id: id2,
428
453
  label,
429
454
  renameClass,
430
455
  selected,
431
- children
456
+ children,
457
+ disabled
432
458
  }) => {
433
459
  const {
434
460
  ref: editableRef,
@@ -446,23 +472,23 @@ var ClassItem = ({
446
472
  variant: "popover",
447
473
  disableAutoFocus: true
448
474
  });
449
- return /* @__PURE__ */ React4.createElement(Stack2, { direction: "row", alignItems: "center", gap: 1, flexGrow: 1, flexShrink: 0 }, /* @__PURE__ */ React4.createElement(
475
+ return /* @__PURE__ */ React5.createElement(Stack2, { direction: "row", alignItems: "center", gap: 1, flexGrow: 1, flexShrink: 0 }, /* @__PURE__ */ React5.createElement(
450
476
  StyledListItem,
451
477
  {
452
478
  component: "div",
453
479
  disablePadding: true,
454
480
  disableGutters: true,
455
- secondaryAction: /* @__PURE__ */ React4.createElement(
481
+ secondaryAction: /* @__PURE__ */ React5.createElement(
456
482
  Tooltip,
457
483
  {
458
484
  placement: "top",
459
485
  className: "class-item-more-actions",
460
486
  title: __4("More actions", "elementor")
461
487
  },
462
- /* @__PURE__ */ React4.createElement(IconButton, { size: "tiny", ...bindTrigger(popupState), "aria-label": "More actions" }, /* @__PURE__ */ React4.createElement(DotsVerticalIcon, { fontSize: "tiny" }))
488
+ /* @__PURE__ */ React5.createElement(IconButton, { size: "tiny", ...bindTrigger(popupState), "aria-label": "More actions" }, /* @__PURE__ */ React5.createElement(DotsVerticalIcon, { fontSize: "tiny" }))
463
489
  )
464
490
  },
465
- /* @__PURE__ */ React4.createElement(
491
+ /* @__PURE__ */ React5.createElement(
466
492
  ListItemButton,
467
493
  {
468
494
  dense: true,
@@ -470,6 +496,7 @@ var ClassItem = ({
470
496
  shape: "rounded",
471
497
  onDoubleClick: openEditMode,
472
498
  selected: selected || popupState.isOpen,
499
+ disabled,
473
500
  focusVisibleClassName: "visible-class-item",
474
501
  sx: {
475
502
  minHeight: "36px",
@@ -479,7 +506,7 @@ var ClassItem = ({
479
506
  }
480
507
  }
481
508
  },
482
- /* @__PURE__ */ React4.createElement(Indicator, { isActive: isEditing, isError: !!error }, isEditing ? /* @__PURE__ */ React4.createElement(
509
+ /* @__PURE__ */ React5.createElement(Indicator, { isActive: isEditing, isError: !!error }, isEditing ? /* @__PURE__ */ React5.createElement(
483
510
  EditableField,
484
511
  {
485
512
  ref: editableRef,
@@ -488,10 +515,10 @@ var ClassItem = ({
488
515
  variant: "caption",
489
516
  ...getEditableProps()
490
517
  }
491
- ) : /* @__PURE__ */ React4.createElement(EllipsisWithTooltip, { title: label, as: Typography3, variant: "caption" }))
518
+ ) : /* @__PURE__ */ React5.createElement(EllipsisWithTooltip, { title: label, as: Typography3, variant: "caption" }))
492
519
  ),
493
520
  children,
494
- /* @__PURE__ */ React4.createElement(
521
+ /* @__PURE__ */ React5.createElement(
495
522
  Menu,
496
523
  {
497
524
  ...bindMenu(popupState),
@@ -504,7 +531,7 @@ var ClassItem = ({
504
531
  horizontal: "right"
505
532
  }
506
533
  },
507
- /* @__PURE__ */ React4.createElement(
534
+ /* @__PURE__ */ React5.createElement(
508
535
  MenuItem,
509
536
  {
510
537
  sx: { minWidth: "160px" },
@@ -513,17 +540,17 @@ var ClassItem = ({
513
540
  openEditMode();
514
541
  }
515
542
  },
516
- /* @__PURE__ */ React4.createElement(ListItemText, { primary: __4("Rename", "elementor") })
543
+ /* @__PURE__ */ React5.createElement(ListItemText, { primary: __4("Rename", "elementor") })
517
544
  ),
518
- /* @__PURE__ */ React4.createElement(
545
+ /* @__PURE__ */ React5.createElement(
519
546
  MenuItem,
520
547
  {
521
548
  onClick: () => {
522
549
  popupState.close();
523
- openDialog({ id, label });
550
+ openDialog({ id: id2, label });
524
551
  }
525
552
  },
526
- /* @__PURE__ */ React4.createElement(ListItemText, { primary: __4("Delete", "elementor"), sx: { color: "error.light" } })
553
+ /* @__PURE__ */ React5.createElement(ListItemText, { primary: __4("Delete", "elementor"), sx: { color: "error.light" } })
527
554
  )
528
555
  )
529
556
  ));
@@ -538,7 +565,7 @@ var StyledListItem = styled2(ListItem)`
538
565
  }
539
566
  }
540
567
  `;
541
- var EmptyState = () => /* @__PURE__ */ React4.createElement(Stack2, { alignItems: "center", gap: 3, pt: 4, px: 0.5 }, /* @__PURE__ */ React4.createElement(PhotoIcon, { fontSize: "large" }), /* @__PURE__ */ React4.createElement(StyledHeader, { variant: "subtitle2", component: "h2", color: "text.secondary" }, __4("No CSS classes created yet", "elementor")), /* @__PURE__ */ React4.createElement(Typography3, { align: "center", variant: "caption", color: "text.secondary" }, __4(
568
+ var EmptyState = () => /* @__PURE__ */ React5.createElement(Stack2, { alignItems: "center", gap: 1.5, pt: 10, px: 0.5, maxWidth: "260px", margin: "auto" }, /* @__PURE__ */ React5.createElement(FlippedColorSwatchIcon, { fontSize: "large" }), /* @__PURE__ */ React5.createElement(StyledHeader, { variant: "subtitle2", component: "h2", color: "text.secondary" }, __4("There are no global classes yet.", "elementor")), /* @__PURE__ */ React5.createElement(Typography3, { align: "center", variant: "caption", color: "text.secondary" }, __4(
542
569
  "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.",
543
570
  "elementor"
544
571
  )));
@@ -577,8 +604,8 @@ var validateLabel = (newLabel) => {
577
604
  return null;
578
605
  };
579
606
 
580
- // src/components/class-manager/unsaved-changes-dialog.tsx
581
- import * as React5 from "react";
607
+ // src/components/class-manager/save-changes-dialog.tsx
608
+ import * as React6 from "react";
582
609
  import { useState as useState3 } from "react";
583
610
  import { AlertTriangleFilledIcon } from "@elementor/icons";
584
611
  import {
@@ -589,17 +616,25 @@ import {
589
616
  DialogContentText as DialogContentText2,
590
617
  DialogTitle as DialogTitle2
591
618
  } from "@elementor/ui";
592
- var TITLE_ID2 = "unsaved-changes-dialog";
593
- var UnsavedChangesDialog = ({ children, onClose }) => /* @__PURE__ */ React5.createElement(Dialog2, { open: true, onClose, "aria-labelledby": TITLE_ID2, maxWidth: "xs" }, children);
594
- var UnsavedChangesDialogTitle = ({ children }) => /* @__PURE__ */ React5.createElement(DialogTitle2, { id: TITLE_ID2, display: "flex", alignItems: "center", gap: 1, sx: { lineHeight: 1 } }, /* @__PURE__ */ React5.createElement(AlertTriangleFilledIcon, { color: "secondary" }), children);
595
- var UnsavedChangesDialogContent = ({ children }) => /* @__PURE__ */ React5.createElement(DialogContent2, null, /* @__PURE__ */ React5.createElement(DialogContentText2, { variant: "body2", color: "textPrimary" }, children));
596
- var UnsavedChangesDialogActions = ({ actions }) => {
619
+ var TITLE_ID2 = "save-changes-dialog";
620
+ var SaveChangesDialog = ({ children, onClose }) => /* @__PURE__ */ React6.createElement(Dialog2, { open: true, onClose, "aria-labelledby": TITLE_ID2, maxWidth: "xs" }, children);
621
+ var SaveChangesDialogTitle = ({ children }) => /* @__PURE__ */ React6.createElement(DialogTitle2, { id: TITLE_ID2, display: "flex", alignItems: "center", gap: 1, sx: { lineHeight: 1 } }, /* @__PURE__ */ React6.createElement(AlertTriangleFilledIcon, { color: "secondary" }), children);
622
+ var SaveChangesDialogContent = ({ children }) => /* @__PURE__ */ React6.createElement(DialogContent2, null, children);
623
+ var SaveChangesDialogContentText = (props) => /* @__PURE__ */ React6.createElement(DialogContentText2, { variant: "body2", color: "textPrimary", display: "flex", flexDirection: "column", ...props });
624
+ var SaveChangesDialogActions = ({ actions }) => {
625
+ const [isConfirming, setIsConfirming] = useState3(false);
597
626
  const { cancel, confirm } = actions;
598
- return /* @__PURE__ */ React5.createElement(DialogActions2, null, /* @__PURE__ */ React5.createElement(Button2, { variant: "text", color: "secondary", onClick: cancel.action }, cancel.label), /* @__PURE__ */ React5.createElement(Button2, { variant: "contained", color: "secondary", onClick: confirm.action }, confirm.label));
627
+ const onConfirm = async () => {
628
+ setIsConfirming(true);
629
+ await confirm.action();
630
+ setIsConfirming(false);
631
+ };
632
+ 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));
599
633
  };
600
- UnsavedChangesDialog.Title = UnsavedChangesDialogTitle;
601
- UnsavedChangesDialog.Content = UnsavedChangesDialogContent;
602
- UnsavedChangesDialog.Actions = UnsavedChangesDialogActions;
634
+ SaveChangesDialog.Title = SaveChangesDialogTitle;
635
+ SaveChangesDialog.Content = SaveChangesDialogContent;
636
+ SaveChangesDialog.ContentText = SaveChangesDialogContentText;
637
+ SaveChangesDialog.Actions = SaveChangesDialogActions;
603
638
  var useDialog = () => {
604
639
  const [isOpen, setIsOpen] = useState3(false);
605
640
  const open = () => setIsOpen(true);
@@ -608,31 +643,32 @@ var useDialog = () => {
608
643
  };
609
644
 
610
645
  // src/components/class-manager/class-manager-panel.tsx
646
+ var id = "global-classes-manager";
611
647
  var { panel, usePanelActions } = createPanel({
612
- id: "class-manager-panel",
613
- component: ClassManagerPanel
648
+ id,
649
+ component: ClassManagerPanel,
650
+ onOpen: () => changeEditMode(id),
651
+ onClose: () => changeEditMode("edit"),
652
+ allowedEditModes: ["edit", id]
614
653
  });
615
654
  function ClassManagerPanel() {
616
655
  const isDirty3 = useDirtyState();
617
656
  const { close: closePanel } = usePanelActions();
618
- const {
619
- open: openUnsavedChangesDialog,
620
- close: closeUnsavedChangesDialog,
621
- isOpen: isUnsavedChangesDialogOpen
622
- } = useDialog();
623
- return /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(ErrorBoundary, { fallback: /* @__PURE__ */ React6.createElement(ErrorBoundaryFallback, null) }, /* @__PURE__ */ React6.createElement(Panel, null, /* @__PURE__ */ React6.createElement(PanelHeader, null, /* @__PURE__ */ React6.createElement(Stack3, { p: 1, pl: 2, width: "100%", direction: "row", alignItems: "center" }, /* @__PURE__ */ React6.createElement(PanelHeaderTitle, { sx: { display: "flex", alignItems: "center", gap: 0.5 } }, /* @__PURE__ */ React6.createElement(ColorSwatchIcon, { fontSize: "inherit", sx: { transform: "rotate(90deg)" } }), __5("CSS Class manager", "elementor")), /* @__PURE__ */ React6.createElement(
657
+ const { open: openSaveChangesDialog, close: closeSaveChangesDialog, isOpen: isSaveChangesDialogOpen } = useDialog();
658
+ usePreventUnload();
659
+ return /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(ErrorBoundary, { fallback: /* @__PURE__ */ React7.createElement(ErrorBoundaryFallback, null) }, /* @__PURE__ */ React7.createElement(Panel, null, /* @__PURE__ */ React7.createElement(PanelHeader, null, /* @__PURE__ */ React7.createElement(Stack3, { 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("CSS Class manager", "elementor")), /* @__PURE__ */ React7.createElement(
624
660
  CloseButton,
625
661
  {
626
662
  sx: { marginLeft: "auto" },
627
663
  onClose: () => {
628
664
  if (isDirty3) {
629
- openUnsavedChangesDialog();
665
+ openSaveChangesDialog();
630
666
  return;
631
667
  }
632
668
  closePanel();
633
669
  }
634
670
  }
635
- ))), /* @__PURE__ */ React6.createElement(PanelBody, { px: 2 }, /* @__PURE__ */ React6.createElement(GlobalClassesList, null)), /* @__PURE__ */ React6.createElement(PanelFooter, null, /* @__PURE__ */ React6.createElement(
671
+ ))), /* @__PURE__ */ React7.createElement(PanelBody, { px: 2 }, /* @__PURE__ */ React7.createElement(GlobalClassesList, null)), /* @__PURE__ */ React7.createElement(PanelFooter, null, /* @__PURE__ */ React7.createElement(
636
672
  Button3,
637
673
  {
638
674
  fullWidth: true,
@@ -643,19 +679,19 @@ function ClassManagerPanel() {
643
679
  onClick: publishGlobalClasses
644
680
  },
645
681
  __5("Save changes", "elementor")
646
- )))), /* @__PURE__ */ React6.createElement(ClassManagerIntroduction, null), isUnsavedChangesDialogOpen && /* @__PURE__ */ React6.createElement(UnsavedChangesDialog, null, /* @__PURE__ */ React6.createElement(UnsavedChangesDialog.Title, null, __5("You have unsaved changes", "elementor")), /* @__PURE__ */ React6.createElement(UnsavedChangesDialog.Content, null, __5("You have unsaved changes in the Class Manager.", "elementor"), /* @__PURE__ */ React6.createElement("br", null), __5("To avoid losing your updates, save your changes before leaving.", "elementor")), /* @__PURE__ */ React6.createElement(
647
- UnsavedChangesDialog.Actions,
682
+ )))), /* @__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(
683
+ SaveChangesDialog.Actions,
648
684
  {
649
685
  actions: {
650
686
  cancel: {
651
687
  label: __5("Cancel", "elementor"),
652
- action: closeUnsavedChangesDialog
688
+ action: closeSaveChangesDialog
653
689
  },
654
690
  confirm: {
655
691
  label: __5("Save & Continue", "elementor"),
656
- action: () => {
657
- publishGlobalClasses();
658
- closeUnsavedChangesDialog();
692
+ action: async () => {
693
+ await publishGlobalClasses();
694
+ closeSaveChangesDialog();
659
695
  closePanel();
660
696
  }
661
697
  }
@@ -663,21 +699,66 @@ function ClassManagerPanel() {
663
699
  }
664
700
  )));
665
701
  }
666
- var CloseButton = ({ onClose, ...props }) => /* @__PURE__ */ React6.createElement(IconButton2, { size: "small", color: "secondary", onClick: onClose, "aria-label": "Close", ...props }, /* @__PURE__ */ React6.createElement(XIcon, { fontSize: "small" }));
667
- var ErrorBoundaryFallback = () => /* @__PURE__ */ React6.createElement(Box4, { role: "alert", sx: { minHeight: "100%", p: 2 } }, /* @__PURE__ */ React6.createElement(Alert, { severity: "error", sx: { mb: 2, maxWidth: 400, textAlign: "center" } }, /* @__PURE__ */ React6.createElement("strong", null, __5("Something went wrong", "elementor"))));
702
+ var CloseButton = ({ onClose, ...props }) => /* @__PURE__ */ React7.createElement(IconButton2, { size: "small", color: "secondary", onClick: onClose, "aria-label": "Close", ...props }, /* @__PURE__ */ React7.createElement(XIcon, { fontSize: "small" }));
703
+ 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"))));
704
+ var usePreventUnload = () => {
705
+ const isDirty3 = useDirtyState();
706
+ useEffect(() => {
707
+ const handleBeforeUnload = (event) => {
708
+ if (isDirty3) {
709
+ event.preventDefault();
710
+ }
711
+ };
712
+ window.addEventListener("beforeunload", handleBeforeUnload);
713
+ return () => {
714
+ window.removeEventListener("beforeunload", handleBeforeUnload);
715
+ };
716
+ }, [isDirty3]);
717
+ };
668
718
 
669
719
  // src/components/class-manager/class-manager-button.tsx
670
720
  var ClassManagerButton = () => {
671
- const { open } = usePanelActions();
672
- return /* @__PURE__ */ React7.createElement(Tooltip2, { title: __6("Class manager", "elementor"), placement: "top" }, /* @__PURE__ */ React7.createElement(IconButton3, { onClick: open }, /* @__PURE__ */ React7.createElement(ColorSwatchIcon2, { fontSize: "tiny" })));
721
+ const document = useActiveDocument();
722
+ const { open: openPanel } = usePanelActions();
723
+ const { save: saveDocument } = useActiveDocumentActions();
724
+ const { open: openSaveChangesDialog, close: closeSaveChangesDialog, isOpen: isSaveChangesDialogOpen } = useDialog();
725
+ const handleOpenPanel = () => {
726
+ if (document?.isDirty) {
727
+ openSaveChangesDialog();
728
+ return;
729
+ }
730
+ openPanel();
731
+ };
732
+ return /* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement(Tooltip2, { title: __6("Class manager", "elementor"), placement: "top" }, /* @__PURE__ */ React8.createElement(IconButton3, { onClick: handleOpenPanel }, /* @__PURE__ */ React8.createElement(FlippedColorSwatchIcon, { fontSize: "tiny" }))), isSaveChangesDialogOpen && /* @__PURE__ */ React8.createElement(SaveChangesDialog, null, /* @__PURE__ */ React8.createElement(SaveChangesDialog.Title, null, __6("You have unsaved changes", "elementor")), /* @__PURE__ */ React8.createElement(SaveChangesDialog.Content, null, /* @__PURE__ */ React8.createElement(SaveChangesDialog.ContentText, { sx: { mb: 2 } }, __6(
733
+ "Save your changes before moving to the class manager to ensure all updates are applied and saved.",
734
+ "elementor"
735
+ )), /* @__PURE__ */ React8.createElement(SaveChangesDialog.ContentText, null, __6("If you leave without saving, all changes will be discarded.", "elementor"))), /* @__PURE__ */ React8.createElement(
736
+ SaveChangesDialog.Actions,
737
+ {
738
+ actions: {
739
+ cancel: {
740
+ label: __6("Keep editing", "elementor"),
741
+ action: closeSaveChangesDialog
742
+ },
743
+ confirm: {
744
+ label: __6("Save & Continue", "elementor"),
745
+ action: async () => {
746
+ await saveDocument();
747
+ closeSaveChangesDialog();
748
+ openPanel();
749
+ }
750
+ }
751
+ }
752
+ }
753
+ )));
673
754
  };
674
755
 
675
756
  // src/components/populate-store.tsx
676
- import { useEffect } from "react";
757
+ import { useEffect as useEffect2 } from "react";
677
758
  import { __useDispatch as useDispatch } from "@elementor/store";
678
759
  function PopulateStore() {
679
760
  const dispatch3 = useDispatch();
680
- useEffect(() => {
761
+ useEffect2(() => {
681
762
  apiClient.all().then((res) => {
682
763
  const { data, meta } = res.data;
683
764
  dispatch3(slice.actions.init({ items: data, order: meta.order }));