@elementor/editor-global-classes 3.33.0-99 → 3.35.0-325

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/index.js +990 -428
  2. package/dist/index.js.map +1 -1
  3. package/dist/index.mjs +931 -365
  4. package/dist/index.mjs.map +1 -1
  5. package/package.json +21 -18
  6. package/src/api.ts +4 -0
  7. package/src/components/class-manager/class-manager-button.tsx +15 -1
  8. package/src/components/class-manager/class-manager-panel.tsx +2 -2
  9. package/src/components/class-manager/delete-class.ts +9 -3
  10. package/src/components/class-manager/delete-confirmation-dialog.tsx +2 -2
  11. package/src/components/class-manager/duplicate-label-dialog.tsx +159 -0
  12. package/src/components/class-manager/global-classes-list.tsx +53 -22
  13. package/src/components/convert-local-class-to-global-class.tsx +7 -0
  14. package/src/components/css-class-usage/components/css-class-usage-popover.tsx +10 -1
  15. package/src/components/css-class-usage/components/css-class-usage-trigger.tsx +22 -7
  16. package/src/components/search-and-filter/components/filter/active-filters.tsx +8 -0
  17. package/src/components/search-and-filter/components/filter/clear-icon-button.tsx +12 -3
  18. package/src/components/search-and-filter/components/filter/css-class-filter.tsx +10 -0
  19. package/src/components/search-and-filter/components/filter/filter-list.tsx +7 -0
  20. package/src/components/search-and-filter/components/search/class-manager-search.tsx +6 -0
  21. package/src/components/search-and-filter/context.tsx +12 -2
  22. package/src/errors.ts +5 -0
  23. package/src/global-classes-styles-provider.ts +13 -3
  24. package/src/hooks/use-css-class-by-id.ts +8 -0
  25. package/src/hooks/use-prefetch-css-class-usage.ts +6 -0
  26. package/src/init.ts +14 -5
  27. package/src/mcp-integration/classes-resource.ts +20 -0
  28. package/src/mcp-integration/index.ts +15 -0
  29. package/src/mcp-integration/mcp-apply-unapply-global-classes.ts +117 -0
  30. package/src/mcp-integration/mcp-get-global-class-usages.ts +72 -0
  31. package/src/save-global-classes.tsx +55 -0
  32. package/src/store.ts +15 -0
  33. package/src/sync-with-document-save.ts +9 -6
  34. package/src/sync-with-document.tsx +19 -0
  35. package/src/utils/tracking.ts +206 -0
  36. package/src/components/class-manager/save-changes-dialog.tsx +0 -92
  37. package/src/save-global-classes.ts +0 -42
package/dist/index.mjs CHANGED
@@ -6,26 +6,26 @@ import {
6
6
  registerStyleProviderToColors
7
7
  } from "@elementor/editor-editing-panel";
8
8
  import { __registerPanel as registerPanel } from "@elementor/editor-panels";
9
- import { stylesRepository } from "@elementor/editor-styles-repository";
10
- import { __privateListenTo as listenTo, v1ReadyEvent } from "@elementor/editor-v1-adapters";
9
+ import { stylesRepository as stylesRepository2 } from "@elementor/editor-styles-repository";
11
10
  import { __registerSlice as registerSlice } from "@elementor/store";
12
11
 
13
12
  // src/components/class-manager/class-manager-button.tsx
14
- import * as React18 from "react";
13
+ import * as React19 from "react";
15
14
  import {
16
15
  __useActiveDocument as useActiveDocument2,
17
16
  __useActiveDocumentActions as useActiveDocumentActions
18
17
  } from "@elementor/editor-documents";
19
18
  import { useUserStylesCapability } from "@elementor/editor-styles-repository";
19
+ import { SaveChangesDialog as SaveChangesDialog2, useDialog as useDialog2 } from "@elementor/editor-ui";
20
20
  import { IconButton as IconButton5, Tooltip as Tooltip6 } from "@elementor/ui";
21
- import { __ as __14 } from "@wordpress/i18n";
21
+ import { __ as __15 } from "@wordpress/i18n";
22
22
 
23
23
  // src/global-classes-styles-provider.ts
24
24
  import { generateId } from "@elementor/editor-styles";
25
25
  import { createStylesProvider } from "@elementor/editor-styles-repository";
26
26
  import {
27
27
  __dispatch as dispatch,
28
- __getState as getState,
28
+ __getState as getState2,
29
29
  __subscribeWithSelector as subscribeWithSelector
30
30
  } from "@elementor/store";
31
31
  import { __ } from "@wordpress/i18n";
@@ -56,6 +56,10 @@ var GlobalClassLabelAlreadyExistsError = createError({
56
56
  code: "global_class_label_already_exists",
57
57
  message: "Class with this name already exists."
58
58
  });
59
+ var GlobalClassTrackingError = createError({
60
+ code: "global_class_tracking_error",
61
+ message: "Error tracking global classes event."
62
+ });
59
63
 
60
64
  // src/store.ts
61
65
  import { mergeProps } from "@elementor/editor-props";
@@ -179,6 +183,13 @@ var slice = createSlice({
179
183
  state.data.items[payload.style.id] = mergedData;
180
184
  state.isDirty = true;
181
185
  },
186
+ updateMultiple(state, { payload }) {
187
+ localHistory.next(state.data);
188
+ Object.entries(payload).forEach(([id2, { modified }]) => {
189
+ state.data.items[id2].label = modified;
190
+ });
191
+ state.isDirty = false;
192
+ },
182
193
  updateProps(state, {
183
194
  payload
184
195
  }) {
@@ -258,8 +269,161 @@ var selectEmptyCssClass = createSelector(
258
269
  ({ items }) => Object.values(items).filter((cssClass) => cssClass.variants.length === 0)
259
270
  );
260
271
 
272
+ // src/utils/tracking.ts
273
+ import { getMixpanel } from "@elementor/mixpanel";
274
+ import { __getState as getState } from "@elementor/store";
275
+
276
+ // src/api.ts
277
+ import { httpService } from "@elementor/http-client";
278
+ var RESOURCE_URL = "/global-classes";
279
+ var BASE_URL = "elementor/v1";
280
+ var RESOURCE_USAGE_URL = `${RESOURCE_URL}/usage`;
281
+ var apiClient = {
282
+ usage: () => httpService().get(`${BASE_URL}${RESOURCE_USAGE_URL}`),
283
+ all: (context2 = "preview") => httpService().get(`${BASE_URL}${RESOURCE_URL}`, {
284
+ params: { context: context2 }
285
+ }),
286
+ publish: (payload) => httpService().put("elementor/v1" + RESOURCE_URL, payload, {
287
+ params: {
288
+ context: "frontend"
289
+ }
290
+ }),
291
+ saveDraft: (payload) => httpService().put("elementor/v1" + RESOURCE_URL, payload, {
292
+ params: {
293
+ context: "preview"
294
+ }
295
+ })
296
+ };
297
+ var API_ERROR_CODES = {
298
+ DUPLICATED_LABEL: "DUPLICATED_LABEL"
299
+ };
300
+
301
+ // src/components/css-class-usage/utils.ts
302
+ var transformData = (data) => Object.entries(data).reduce((acc, [key, value]) => {
303
+ acc[key] = {
304
+ content: value || [],
305
+ total: value.reduce((total, val) => total + (val?.total || 0), 0)
306
+ };
307
+ return acc;
308
+ }, {});
309
+
310
+ // service/css-class-usage-service.ts
311
+ var fetchCssClassUsage = async () => {
312
+ const response = await apiClient.usage();
313
+ return transformData(response?.data?.data || {});
314
+ };
315
+
316
+ // src/utils/tracking.ts
317
+ var trackGlobalClasses = async (payload) => {
318
+ const { runAction } = payload;
319
+ const data = await getSanitizedData(payload);
320
+ if (data) {
321
+ track(data);
322
+ if (data.event === "classCreated" && "classId" in data) {
323
+ fireClassApplied(data.classId);
324
+ }
325
+ }
326
+ runAction?.();
327
+ };
328
+ var fireClassApplied = async (classId) => {
329
+ const appliedInfo = await getAppliedInfo(classId);
330
+ track({
331
+ event: "classApplied",
332
+ classId,
333
+ ...appliedInfo,
334
+ totalInstancesAfterApply: 1
335
+ });
336
+ };
337
+ var getSanitizedData = async (payload) => {
338
+ switch (payload.event) {
339
+ case "classApplied":
340
+ if ("classId" in payload && payload.classId) {
341
+ const appliedInfo = await getAppliedInfo(payload.classId);
342
+ return { ...payload, ...appliedInfo };
343
+ }
344
+ break;
345
+ case "classRemoved":
346
+ if ("classId" in payload && payload.classId) {
347
+ const deleteInfo = getRemovedInfo(payload.classId);
348
+ return { ...payload, ...deleteInfo };
349
+ }
350
+ break;
351
+ case "classDeleted":
352
+ if ("classId" in payload && payload.classId) {
353
+ const deleteInfo = await trackDeleteClass(payload.classId);
354
+ return { ...payload, ...deleteInfo };
355
+ }
356
+ break;
357
+ case "classCreated":
358
+ if ("source" in payload && payload.source !== "created") {
359
+ if ("classId" in payload && payload.classId) {
360
+ return { ...payload, classTitle: getCssClass(payload.classId).label };
361
+ }
362
+ }
363
+ return payload;
364
+ case "classStateClicked":
365
+ if ("classId" in payload && payload.classId) {
366
+ return { ...payload, classTitle: getCssClass(payload.classId).label };
367
+ }
368
+ break;
369
+ default:
370
+ return payload;
371
+ }
372
+ };
373
+ var track = (data) => {
374
+ const { dispatchEvent, config } = getMixpanel();
375
+ if (!config?.names?.global_classes?.[data.event]) {
376
+ console.error("Global class tracking event not found", { event: data.event });
377
+ return;
378
+ }
379
+ const name = config.names.global_classes[data.event];
380
+ const { event, ...eventData } = data;
381
+ try {
382
+ dispatchEvent?.(name, {
383
+ event,
384
+ properties: {
385
+ ...eventData
386
+ }
387
+ });
388
+ } catch (error) {
389
+ throw new GlobalClassTrackingError({ cause: error });
390
+ }
391
+ };
392
+ var extractCssClassData = (classId) => {
393
+ const cssClass = getCssClass(classId);
394
+ const classTitle = cssClass.label;
395
+ return { classTitle };
396
+ };
397
+ var getCssClass = (classId) => {
398
+ const cssClass = selectClass(getState(), classId);
399
+ if (!cssClass) {
400
+ throw new Error(`CSS class with ID ${classId} not found`);
401
+ }
402
+ return cssClass;
403
+ };
404
+ var trackDeleteClass = async (classId) => {
405
+ const totalInstances = await getTotalInstancesByCssClassID(classId);
406
+ const classTitle = getCssClass(classId).label;
407
+ return { totalInstances, classTitle };
408
+ };
409
+ var getTotalInstancesByCssClassID = async (classId) => {
410
+ const cssClassUsage = await fetchCssClassUsage();
411
+ return cssClassUsage[classId]?.total ?? 1;
412
+ };
413
+ var getAppliedInfo = async (classId) => {
414
+ const { classTitle } = extractCssClassData(classId);
415
+ const totalInstancesAfterApply = await getTotalInstancesByCssClassID(classId) + 1;
416
+ return { classTitle, totalInstancesAfterApply };
417
+ };
418
+ var getRemovedInfo = (classId) => {
419
+ const { classTitle } = extractCssClassData(classId);
420
+ return {
421
+ classTitle
422
+ };
423
+ };
424
+
261
425
  // src/global-classes-styles-provider.ts
262
- var MAX_CLASSES = 50;
426
+ var MAX_CLASSES = 100;
263
427
  var GLOBAL_CLASSES_PROVIDER_KEY = "global-classes";
264
428
  var globalClassesStylesProvider = createStylesProvider({
265
429
  key: GLOBAL_CLASSES_PROVIDER_KEY,
@@ -272,13 +436,17 @@ var globalClassesStylesProvider = createStylesProvider({
272
436
  subscribe: (cb) => subscribeWithStates(cb),
273
437
  capabilities: getCapabilities(),
274
438
  actions: {
275
- all: () => selectOrderedClasses(getState()),
276
- get: (id2) => selectClass(getState(), id2),
439
+ all: () => {
440
+ const selectAllClasses = selectOrderedClasses(getState2());
441
+ localStorage.setItem("elementor-global-classes", JSON.stringify(selectAllClasses));
442
+ return selectAllClasses;
443
+ },
444
+ get: (id2) => selectClass(getState2(), id2),
277
445
  resolveCssName: (id2) => {
278
- return selectClass(getState(), id2)?.label ?? id2;
446
+ return selectClass(getState2(), id2)?.label ?? id2;
279
447
  },
280
448
  create: (label, variants = []) => {
281
- const classes = selectGlobalClasses(getState());
449
+ const classes = selectGlobalClasses(getState2());
282
450
  const existingLabels = Object.values(classes).map((style) => style.label);
283
451
  if (existingLabels.includes(label)) {
284
452
  throw new GlobalClassLabelAlreadyExistsError({ context: { label } });
@@ -323,11 +491,16 @@ var globalClassesStylesProvider = createStylesProvider({
323
491
  props: {}
324
492
  })
325
493
  );
494
+ },
495
+ tracking: (data) => {
496
+ trackGlobalClasses(data).catch((error) => {
497
+ throw new GlobalClassTrackingError({ cause: error });
498
+ });
326
499
  }
327
500
  }
328
501
  });
329
502
  var subscribeWithStates = (cb) => {
330
- let previousState = selectData(getState());
503
+ let previousState = selectData(getState2());
331
504
  return subscribeWithSelector(
332
505
  (state) => state.globalClasses,
333
506
  (currentState) => {
@@ -340,43 +513,6 @@ var subscribeWithStates = (cb) => {
340
513
  // src/hooks/use-prefetch-css-class-usage.ts
341
514
  import { useQueryClient } from "@elementor/query";
342
515
 
343
- // src/api.ts
344
- import { httpService } from "@elementor/http-client";
345
- var RESOURCE_URL = "/global-classes";
346
- var BASE_URL = "elementor/v1";
347
- var RESOURCE_USAGE_URL = `${RESOURCE_URL}/usage`;
348
- var apiClient = {
349
- usage: () => httpService().get(`${BASE_URL}${RESOURCE_USAGE_URL}`),
350
- all: (context2 = "preview") => httpService().get(`${BASE_URL}${RESOURCE_URL}`, {
351
- params: { context: context2 }
352
- }),
353
- publish: (payload) => httpService().put("elementor/v1" + RESOURCE_URL, payload, {
354
- params: {
355
- context: "frontend"
356
- }
357
- }),
358
- saveDraft: (payload) => httpService().put("elementor/v1" + RESOURCE_URL, payload, {
359
- params: {
360
- context: "preview"
361
- }
362
- })
363
- };
364
-
365
- // src/components/css-class-usage/utils.ts
366
- var transformData = (data) => Object.entries(data).reduce((acc, [key, value]) => {
367
- acc[key] = {
368
- content: value || [],
369
- total: value.reduce((total, val) => total + (val?.total || 0), 0)
370
- };
371
- return acc;
372
- }, {});
373
-
374
- // service/css-class-usage-service.ts
375
- var fetchCssClassUsage = async () => {
376
- const response = await apiClient.usage();
377
- return transformData(response.data.data);
378
- };
379
-
380
516
  // src/components/css-class-usage/types.ts
381
517
  var QUERY_KEY = "css-classes-usage";
382
518
 
@@ -389,10 +525,15 @@ function usePrefetchCssClassUsage() {
389
525
  });
390
526
  return { prefetchClassesUsage };
391
527
  }
528
+ var PrefetchCssClassUsage = () => {
529
+ const { prefetchClassesUsage } = usePrefetchCssClassUsage();
530
+ prefetchClassesUsage();
531
+ return null;
532
+ };
392
533
 
393
534
  // src/components/class-manager/class-manager-panel.tsx
394
- import * as React17 from "react";
395
- import { useEffect as useEffect2 } from "react";
535
+ import * as React18 from "react";
536
+ import { useEffect as useEffect3 } from "react";
396
537
  import { setDocumentModifiedStatus } from "@elementor/editor-documents";
397
538
  import {
398
539
  __createPanel as createPanel,
@@ -402,23 +543,23 @@ import {
402
543
  PanelHeader,
403
544
  PanelHeaderTitle
404
545
  } from "@elementor/editor-panels";
405
- import { ThemeProvider } from "@elementor/editor-ui";
546
+ import { SaveChangesDialog, ThemeProvider, useDialog } from "@elementor/editor-ui";
406
547
  import { changeEditMode } from "@elementor/editor-v1-adapters";
407
548
  import { XIcon } from "@elementor/icons";
408
549
  import { useMutation } from "@elementor/query";
409
550
  import { __dispatch as dispatch4 } from "@elementor/store";
410
551
  import {
411
- Alert,
412
- Box as Box9,
552
+ Alert as Alert2,
553
+ Box as Box10,
413
554
  Button as Button3,
414
555
  Chip as Chip4,
415
- DialogHeader,
416
- Divider as Divider3,
556
+ DialogHeader as DialogHeader2,
557
+ Divider as Divider4,
417
558
  ErrorBoundary,
418
559
  IconButton as IconButton4,
419
- Stack as Stack8
560
+ Stack as Stack9
420
561
  } from "@elementor/ui";
421
- import { __ as __13 } from "@wordpress/i18n";
562
+ import { __ as __14 } from "@wordpress/i18n";
422
563
 
423
564
  // src/hooks/use-classes-order.ts
424
565
  import { __useSelector as useSelector } from "@elementor/store";
@@ -447,9 +588,17 @@ var INIT_CHECKED_FILTERS = {
447
588
  };
448
589
  var SearchAndFilterProvider = ({ children }) => {
449
590
  const [filters, setFilters] = React.useState(INIT_CHECKED_FILTERS);
591
+ const getInitialSearchValue = () => {
592
+ const storedValue = localStorage.getItem("elementor-global-classes-search");
593
+ if (storedValue) {
594
+ localStorage.removeItem("elementor-global-classes-search");
595
+ return storedValue;
596
+ }
597
+ return "";
598
+ };
450
599
  const { debouncedValue, inputValue, handleChange } = useDebounceState({
451
600
  delay: 300,
452
- initialValue: ""
601
+ initialValue: getInitialSearchValue()
453
602
  });
454
603
  const onClearSearch = () => {
455
604
  handleChange("");
@@ -580,25 +729,150 @@ var useFilters = () => {
580
729
  }, [filters, allFilters]);
581
730
  };
582
731
 
583
- // src/save-global-classes.ts
584
- import { __dispatch as dispatch2, __getState as getState2 } from "@elementor/store";
732
+ // src/save-global-classes.tsx
733
+ import * as React3 from "react";
734
+ import { openDialog } from "@elementor/editor-ui";
735
+ import { __dispatch as dispatch2, __getState as getState3 } from "@elementor/store";
585
736
  import { hash } from "@elementor/utils";
586
- async function saveGlobalClasses({ context: context2 }) {
587
- const state = selectData(getState2());
588
- if (context2 === "preview") {
589
- await apiClient.saveDraft({
590
- items: state.items,
591
- order: state.order,
592
- changes: calculateChanges(state, selectPreviewInitialData(getState2()))
737
+
738
+ // src/components/class-manager/duplicate-label-dialog.tsx
739
+ import * as React2 from "react";
740
+ import { closeDialog, EllipsisWithTooltip } from "@elementor/editor-ui";
741
+ import { InfoCircleFilledIcon } from "@elementor/icons";
742
+ import {
743
+ Alert,
744
+ Box,
745
+ Button,
746
+ DialogActions,
747
+ DialogContent,
748
+ DialogHeader,
749
+ Divider,
750
+ Icon,
751
+ Stack,
752
+ Typography
753
+ } from "@elementor/ui";
754
+ import { __ as __2 } from "@wordpress/i18n";
755
+ var DUP_PREFIX = "DUP_";
756
+ var DuplicateLabelDialog = ({
757
+ modifiedLabels,
758
+ onApprove
759
+ }) => {
760
+ const handleButtonClick = () => {
761
+ localStorage.setItem("elementor-global-classes-search", DUP_PREFIX);
762
+ onApprove?.();
763
+ closeDialog();
764
+ };
765
+ return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(DialogHeader, { logo: false }, /* @__PURE__ */ React2.createElement(Box, { display: "flex", alignItems: "center", gap: 1 }, /* @__PURE__ */ React2.createElement(Icon, { color: "secondary" }, /* @__PURE__ */ React2.createElement(InfoCircleFilledIcon, { fontSize: "medium" })), /* @__PURE__ */ React2.createElement(Typography, { variant: "subtitle1" }, __2("We've published your page and updated class names.", "elementor")))), /* @__PURE__ */ React2.createElement(DialogContent, null, /* @__PURE__ */ React2.createElement(Stack, { spacing: 2, direction: "column" }, /* @__PURE__ */ React2.createElement(Typography, { variant: "body2" }, __2(
766
+ "Some new classes used the same names as existing ones. To prevent conflicts, we added the prefix",
767
+ "elementor"
768
+ ), /* @__PURE__ */ React2.createElement("strong", null, " ", DUP_PREFIX)), /* @__PURE__ */ React2.createElement(Box, null, /* @__PURE__ */ React2.createElement(
769
+ Box,
770
+ {
771
+ sx: {
772
+ width: "100%",
773
+ display: "flex",
774
+ gap: 2,
775
+ alignItems: "flex-start"
776
+ }
777
+ },
778
+ /* @__PURE__ */ React2.createElement(
779
+ Typography,
780
+ {
781
+ variant: "subtitle2",
782
+ sx: {
783
+ fontWeight: "bold",
784
+ flex: 1,
785
+ flexShrink: 1,
786
+ flexGrow: 1,
787
+ minWidth: 0
788
+ }
789
+ },
790
+ __2("Before", "elementor")
791
+ ),
792
+ /* @__PURE__ */ React2.createElement(
793
+ Typography,
794
+ {
795
+ variant: "subtitle2",
796
+ sx: {
797
+ minWidth: "200px",
798
+ fontWeight: "bold",
799
+ flexShrink: 0,
800
+ flexGrow: 0,
801
+ width: "200px",
802
+ maxWidth: "200px"
803
+ }
804
+ },
805
+ __2("After", "elementor")
806
+ )
807
+ ), /* @__PURE__ */ React2.createElement(Divider, { sx: { mt: 0.5, mb: 0.5 } }), /* @__PURE__ */ React2.createElement(Stack, { direction: "column", gap: 0.5, sx: { pb: 2 } }, Object.values(modifiedLabels).map(({ original, modified }, index) => /* @__PURE__ */ React2.createElement(
808
+ Box,
809
+ {
810
+ key: index,
811
+ sx: {
812
+ width: "100%",
813
+ display: "flex",
814
+ gap: 2,
815
+ alignItems: "flex-start"
816
+ }
817
+ },
818
+ /* @__PURE__ */ React2.createElement(
819
+ Box,
820
+ {
821
+ sx: {
822
+ flex: 1,
823
+ flexShrink: 1,
824
+ flexGrow: 1,
825
+ minWidth: 0
826
+ }
827
+ },
828
+ /* @__PURE__ */ React2.createElement(EllipsisWithTooltip, { title: original }, /* @__PURE__ */ React2.createElement(Typography, { variant: "body2", sx: { color: "text.secondary" } }, original))
829
+ ),
830
+ /* @__PURE__ */ React2.createElement(
831
+ Box,
832
+ {
833
+ sx: {
834
+ minWidth: "200px",
835
+ flexShrink: 0,
836
+ flexGrow: 0,
837
+ width: "200px",
838
+ maxWidth: "200px"
839
+ }
840
+ },
841
+ /* @__PURE__ */ React2.createElement(EllipsisWithTooltip, { title: modified }, /* @__PURE__ */ React2.createElement(Typography, { variant: "body2", sx: { color: "text.primary" } }, modified))
842
+ )
843
+ ))), /* @__PURE__ */ React2.createElement(Box, null, /* @__PURE__ */ React2.createElement(Alert, { severity: "info", size: "small", color: "secondary" }, /* @__PURE__ */ React2.createElement("strong", null, __2("Your designs and classes are safe.", "elementor")), __2(
844
+ "Only the prefixes were added. Find them in Class Manager by searching",
845
+ "elementor"
846
+ ), /* @__PURE__ */ React2.createElement("strong", null, DUP_PREFIX)))))), /* @__PURE__ */ React2.createElement(DialogActions, null, /* @__PURE__ */ React2.createElement(Button, { color: "secondary", variant: "text", onClick: handleButtonClick }, __2("Go to Class Manager", "elementor")), /* @__PURE__ */ React2.createElement(Button, { color: "secondary", variant: "contained", onClick: closeDialog }, __2("Done", "elementor"))));
847
+ };
848
+
849
+ // src/save-global-classes.tsx
850
+ async function saveGlobalClasses({ context: context2, onApprove }) {
851
+ const state = selectData(getState3());
852
+ const apiAction = context2 === "preview" ? apiClient.saveDraft : apiClient.publish;
853
+ const currentContext = context2 === "preview" ? selectPreviewInitialData : selectFrontendInitialData;
854
+ const response = await apiAction({
855
+ items: state.items,
856
+ order: state.order,
857
+ changes: calculateChanges(state, currentContext(getState3()))
858
+ });
859
+ dispatch2(slice.actions.reset({ context: context2 }));
860
+ if (response?.data?.data?.code === API_ERROR_CODES.DUPLICATED_LABEL) {
861
+ dispatch2(slice.actions.updateMultiple(response.data.data.modifiedLabels));
862
+ trackGlobalClasses({
863
+ event: "classPublishConflict",
864
+ numOfConflicts: Object.keys(response.data.data.modifiedLabels).length
593
865
  });
594
- } else {
595
- await apiClient.publish({
596
- items: state.items,
597
- order: state.order,
598
- changes: calculateChanges(state, selectFrontendInitialData(getState2()))
866
+ openDialog({
867
+ component: /* @__PURE__ */ React3.createElement(
868
+ DuplicateLabelDialog,
869
+ {
870
+ modifiedLabels: response.data.data.modifiedLabels || [],
871
+ onApprove
872
+ }
873
+ )
599
874
  });
600
875
  }
601
- dispatch2(slice.actions.reset({ context: context2 }));
602
876
  }
603
877
  function calculateChanges(state, initialData) {
604
878
  const stateIds = Object.keys(state.items);
@@ -613,19 +887,26 @@ function calculateChanges(state, initialData) {
613
887
  }
614
888
 
615
889
  // src/components/search-and-filter/components/filter/active-filters.tsx
616
- import * as React4 from "react";
617
- import { Chip as Chip2, Stack as Stack2 } from "@elementor/ui";
618
- import { __ as __3 } from "@wordpress/i18n";
890
+ import * as React6 from "react";
891
+ import { Chip as Chip2, Stack as Stack3 } from "@elementor/ui";
892
+ import { __ as __4 } from "@wordpress/i18n";
619
893
 
620
894
  // src/components/search-and-filter/components/filter/clear-icon-button.tsx
621
- import * as React2 from "react";
895
+ import * as React4 from "react";
622
896
  import { BrushBigIcon } from "@elementor/icons";
623
- import { Box, IconButton, styled, Tooltip } from "@elementor/ui";
624
- var ClearIconButton = ({ tooltipText, sx }) => {
897
+ import { Box as Box2, IconButton, styled, Tooltip } from "@elementor/ui";
898
+ var ClearIconButton = ({ tooltipText, sx, trigger }) => {
625
899
  const {
626
900
  filters: { onClearFilter }
627
901
  } = useSearchAndFilters();
628
- return /* @__PURE__ */ React2.createElement(Tooltip, { title: tooltipText, placement: "top", disableInteractive: true }, /* @__PURE__ */ React2.createElement(Box, null, /* @__PURE__ */ React2.createElement(CustomIconButton, { "aria-label": tooltipText, size: "tiny", onClick: onClearFilter, sx }, /* @__PURE__ */ React2.createElement(BrushBigIcon, { fontSize: "tiny" }))));
902
+ const handleClearFilters = () => {
903
+ onClearFilter(trigger);
904
+ trackGlobalClasses({
905
+ event: "classManagerFilterCleared",
906
+ trigger
907
+ });
908
+ };
909
+ return /* @__PURE__ */ React4.createElement(Tooltip, { title: tooltipText, placement: "top", disableInteractive: true }, /* @__PURE__ */ React4.createElement(Box2, null, /* @__PURE__ */ React4.createElement(CustomIconButton, { "aria-label": tooltipText, size: "tiny", onClick: handleClearFilters, sx }, /* @__PURE__ */ React4.createElement(BrushBigIcon, { fontSize: "tiny" }))));
629
910
  };
630
911
  var CustomIconButton = styled(IconButton)(({ theme }) => ({
631
912
  "&.Mui-disabled": {
@@ -637,13 +918,13 @@ var CustomIconButton = styled(IconButton)(({ theme }) => ({
637
918
  }));
638
919
 
639
920
  // src/components/search-and-filter/components/filter/filter-list.tsx
640
- import * as React3 from "react";
641
- import { Checkbox, Chip, MenuItem, MenuList, Stack, Typography } from "@elementor/ui";
642
- import { __ as __2 } from "@wordpress/i18n";
921
+ import * as React5 from "react";
922
+ import { Checkbox, Chip, MenuItem, MenuList, Stack as Stack2, Typography as Typography2 } from "@elementor/ui";
923
+ import { __ as __3 } from "@wordpress/i18n";
643
924
  var filterConfig = {
644
- unused: __2("Unused", "elementor"),
645
- empty: __2("Empty", "elementor"),
646
- onThisPage: __2("On this page", "elementor")
925
+ unused: __3("Unused", "elementor"),
926
+ empty: __3("Empty", "elementor"),
927
+ onThisPage: __3("On this page", "elementor")
647
928
  };
648
929
  var FilterList = () => {
649
930
  const {
@@ -652,31 +933,37 @@ var FilterList = () => {
652
933
  const filteredCssClass = useFilteredCssClassUsage();
653
934
  const handleOnClick = (value) => {
654
935
  setFilters((prev) => ({ ...prev, [value]: !prev[value] }));
936
+ trackGlobalClasses({
937
+ event: "classManagerFilterUsed",
938
+ action: filters[value] ? "remove" : "apply",
939
+ type: value,
940
+ trigger: "menu"
941
+ });
655
942
  };
656
- return /* @__PURE__ */ React3.createElement(MenuList, null, /* @__PURE__ */ React3.createElement(MenuItem, { onClick: () => handleOnClick("unused") }, /* @__PURE__ */ React3.createElement(
943
+ return /* @__PURE__ */ React5.createElement(MenuList, null, /* @__PURE__ */ React5.createElement(MenuItem, { onClick: () => handleOnClick("unused") }, /* @__PURE__ */ React5.createElement(
657
944
  LabeledCheckbox,
658
945
  {
659
946
  label: filterConfig.unused,
660
947
  checked: filters.unused,
661
- suffix: /* @__PURE__ */ React3.createElement(Chip, { size: "tiny", sx: { ml: "auto" }, label: filteredCssClass.unused.length })
948
+ suffix: /* @__PURE__ */ React5.createElement(Chip, { size: "tiny", sx: { ml: "auto" }, label: filteredCssClass.unused.length })
662
949
  }
663
- )), /* @__PURE__ */ React3.createElement(MenuItem, { onClick: () => handleOnClick("empty") }, /* @__PURE__ */ React3.createElement(
950
+ )), /* @__PURE__ */ React5.createElement(MenuItem, { onClick: () => handleOnClick("empty") }, /* @__PURE__ */ React5.createElement(
664
951
  LabeledCheckbox,
665
952
  {
666
953
  label: filterConfig.empty,
667
954
  checked: filters.empty,
668
- suffix: /* @__PURE__ */ React3.createElement(Chip, { size: "tiny", sx: { ml: "auto" }, label: filteredCssClass.empty.length })
955
+ suffix: /* @__PURE__ */ React5.createElement(Chip, { size: "tiny", sx: { ml: "auto" }, label: filteredCssClass.empty.length })
669
956
  }
670
- )), /* @__PURE__ */ React3.createElement(MenuItem, { onClick: () => handleOnClick("onThisPage") }, /* @__PURE__ */ React3.createElement(
957
+ )), /* @__PURE__ */ React5.createElement(MenuItem, { onClick: () => handleOnClick("onThisPage") }, /* @__PURE__ */ React5.createElement(
671
958
  LabeledCheckbox,
672
959
  {
673
960
  label: filterConfig.onThisPage,
674
961
  checked: filters.onThisPage,
675
- suffix: /* @__PURE__ */ React3.createElement(Chip, { size: "tiny", sx: { ml: "auto" }, label: filteredCssClass.onThisPage.length })
962
+ suffix: /* @__PURE__ */ React5.createElement(Chip, { size: "tiny", sx: { ml: "auto" }, label: filteredCssClass.onThisPage.length })
676
963
  }
677
964
  )));
678
965
  };
679
- var LabeledCheckbox = ({ label, suffix, checked }) => /* @__PURE__ */ React3.createElement(Stack, { direction: "row", alignItems: "center", gap: 0.5, flex: 1 }, /* @__PURE__ */ React3.createElement(
966
+ var LabeledCheckbox = ({ label, suffix, checked }) => /* @__PURE__ */ React5.createElement(Stack2, { direction: "row", alignItems: "center", gap: 0.5, flex: 1 }, /* @__PURE__ */ React5.createElement(
680
967
  Checkbox,
681
968
  {
682
969
  size: "small",
@@ -689,7 +976,7 @@ var LabeledCheckbox = ({ label, suffix, checked }) => /* @__PURE__ */ React3.cre
689
976
  }
690
977
  }
691
978
  }
692
- ), /* @__PURE__ */ React3.createElement(Typography, { variant: "caption", sx: { color: "text.secondary" } }, label), suffix);
979
+ ), /* @__PURE__ */ React5.createElement(Typography2, { variant: "caption", sx: { color: "text.secondary" } }, label), suffix);
693
980
 
694
981
  // src/components/search-and-filter/components/filter/active-filters.tsx
695
982
  var ActiveFilters = () => {
@@ -698,10 +985,16 @@ var ActiveFilters = () => {
698
985
  } = useSearchAndFilters();
699
986
  const handleRemove = (key) => {
700
987
  setFilters((prev) => ({ ...prev, [key]: false }));
988
+ trackGlobalClasses({
989
+ event: "classManagerFilterUsed",
990
+ action: "remove",
991
+ type: key,
992
+ trigger: "header"
993
+ });
701
994
  };
702
995
  const activeKeys = Object.keys(filters).filter((key) => filters[key]);
703
996
  const showClearIcon = activeKeys.length > 0;
704
- return /* @__PURE__ */ React4.createElement(Stack2, { direction: "row", alignItems: "center", justifyContent: "space-between" }, /* @__PURE__ */ React4.createElement(Stack2, { direction: "row", gap: 0.5, alignItems: "center", flexWrap: "wrap" }, activeKeys.map((key) => /* @__PURE__ */ React4.createElement(
997
+ return /* @__PURE__ */ React6.createElement(Stack3, { direction: "row", alignItems: "center", justifyContent: "space-between" }, /* @__PURE__ */ React6.createElement(Stack3, { direction: "row", gap: 0.5, alignItems: "center", flexWrap: "wrap" }, activeKeys.map((key) => /* @__PURE__ */ React6.createElement(
705
998
  Chip2,
706
999
  {
707
1000
  key,
@@ -710,10 +1003,11 @@ var ActiveFilters = () => {
710
1003
  sx: chipSx,
711
1004
  size: "tiny"
712
1005
  }
713
- ))), showClearIcon && /* @__PURE__ */ React4.createElement(
1006
+ ))), showClearIcon && /* @__PURE__ */ React6.createElement(
714
1007
  ClearIconButton,
715
1008
  {
716
- tooltipText: __3("Clear Filters", "elementor"),
1009
+ trigger: "header",
1010
+ tooltipText: __4("Clear Filters", "elementor"),
717
1011
  sx: { margin: "0 0 auto auto" }
718
1012
  }
719
1013
  ));
@@ -729,11 +1023,11 @@ var chipSx = {
729
1023
  };
730
1024
 
731
1025
  // src/components/search-and-filter/components/filter/css-class-filter.tsx
732
- import * as React5 from "react";
1026
+ import * as React7 from "react";
733
1027
  import { PopoverBody, PopoverHeader } from "@elementor/editor-ui";
734
1028
  import { FilterIcon } from "@elementor/icons";
735
- import { bindPopover, bindToggle, Divider, Popover, ToggleButton, Tooltip as Tooltip2, usePopupState } from "@elementor/ui";
736
- import { __ as __4 } from "@wordpress/i18n";
1029
+ import { bindPopover, bindToggle, Divider as Divider2, Popover, ToggleButton, Tooltip as Tooltip2, usePopupState } from "@elementor/ui";
1030
+ import { __ as __5 } from "@wordpress/i18n";
737
1031
  var CssClassFilter = () => {
738
1032
  const {
739
1033
  filters: { filters }
@@ -742,8 +1036,15 @@ var CssClassFilter = () => {
742
1036
  variant: "popover",
743
1037
  disableAutoFocus: true
744
1038
  });
1039
+ React7.useEffect(() => {
1040
+ if (popupState.isOpen) {
1041
+ trackGlobalClasses({
1042
+ event: "classManagerFiltersOpened"
1043
+ });
1044
+ }
1045
+ }, [popupState.isOpen]);
745
1046
  const showCleanIcon = Object.values(filters).some((value) => value);
746
- return /* @__PURE__ */ React5.createElement(React5.Fragment, null, /* @__PURE__ */ React5.createElement(Tooltip2, { title: __4("Filters", "elementor"), placement: "top" }, /* @__PURE__ */ React5.createElement(
1047
+ return /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(Tooltip2, { title: __5("Filters", "elementor"), placement: "top" }, /* @__PURE__ */ React7.createElement(
747
1048
  ToggleButton,
748
1049
  {
749
1050
  value: "filter",
@@ -751,8 +1052,8 @@ var CssClassFilter = () => {
751
1052
  selected: popupState.isOpen,
752
1053
  ...bindToggle(popupState)
753
1054
  },
754
- /* @__PURE__ */ React5.createElement(FilterIcon, { fontSize: "tiny" })
755
- )), /* @__PURE__ */ React5.createElement(
1055
+ /* @__PURE__ */ React7.createElement(FilterIcon, { fontSize: "tiny" })
1056
+ )), /* @__PURE__ */ React7.createElement(
756
1057
  Popover,
757
1058
  {
758
1059
  sx: {
@@ -768,76 +1069,82 @@ var CssClassFilter = () => {
768
1069
  },
769
1070
  ...bindPopover(popupState)
770
1071
  },
771
- /* @__PURE__ */ React5.createElement(
1072
+ /* @__PURE__ */ React7.createElement(
772
1073
  PopoverHeader,
773
1074
  {
774
1075
  actions: showCleanIcon ? [
775
- /* @__PURE__ */ React5.createElement(
1076
+ /* @__PURE__ */ React7.createElement(
776
1077
  ClearIconButton,
777
1078
  {
1079
+ trigger: "menu",
778
1080
  key: "clear-all-button",
779
- tooltipText: __4("Clear all", "elementor")
1081
+ tooltipText: __5("Clear all", "elementor")
780
1082
  }
781
1083
  )
782
1084
  ] : [],
783
1085
  onClose: popupState.close,
784
- title: __4("Filters", "elementor"),
785
- icon: /* @__PURE__ */ React5.createElement(FilterIcon, { fontSize: "tiny" })
1086
+ title: __5("Filters", "elementor"),
1087
+ icon: /* @__PURE__ */ React7.createElement(FilterIcon, { fontSize: "tiny" })
786
1088
  }
787
1089
  ),
788
- /* @__PURE__ */ React5.createElement(
789
- Divider,
1090
+ /* @__PURE__ */ React7.createElement(
1091
+ Divider2,
790
1092
  {
791
1093
  sx: {
792
1094
  borderWidth: "1px 0 0 0"
793
1095
  }
794
1096
  }
795
1097
  ),
796
- /* @__PURE__ */ React5.createElement(PopoverBody, { width: 344, height: 125 }, /* @__PURE__ */ React5.createElement(FilterList, null))
1098
+ /* @__PURE__ */ React7.createElement(PopoverBody, { width: 344, height: 125 }, /* @__PURE__ */ React7.createElement(FilterList, null))
797
1099
  ));
798
1100
  };
799
1101
 
800
1102
  // src/components/search-and-filter/components/search/class-manager-search.tsx
801
- import * as React6 from "react";
1103
+ import * as React8 from "react";
802
1104
  import { SearchIcon } from "@elementor/icons";
803
- import { Box as Box2, InputAdornment, Stack as Stack3, TextField } from "@elementor/ui";
804
- import { __ as __5 } from "@wordpress/i18n";
1105
+ import { Box as Box3, InputAdornment, Stack as Stack4, TextField } from "@elementor/ui";
1106
+ import { __ as __6 } from "@wordpress/i18n";
805
1107
  var ClassManagerSearch = () => {
806
1108
  const {
807
1109
  search: { inputValue, handleChange }
808
1110
  } = useSearchAndFilters();
809
- return /* @__PURE__ */ React6.createElement(Stack3, { direction: "row", gap: 0.5, sx: { width: "100%" } }, /* @__PURE__ */ React6.createElement(Box2, { sx: { flexGrow: 1 } }, /* @__PURE__ */ React6.createElement(
1111
+ return /* @__PURE__ */ React8.createElement(Stack4, { direction: "row", gap: 0.5, sx: { width: "100%" } }, /* @__PURE__ */ React8.createElement(Box3, { sx: { flexGrow: 1 } }, /* @__PURE__ */ React8.createElement(
810
1112
  TextField,
811
1113
  {
812
1114
  role: "search",
813
1115
  fullWidth: true,
814
1116
  size: "tiny",
815
1117
  value: inputValue,
816
- placeholder: __5("Search", "elementor"),
1118
+ onFocus: () => {
1119
+ trackGlobalClasses({
1120
+ event: "classManagerSearched"
1121
+ });
1122
+ },
1123
+ placeholder: __6("Search", "elementor"),
817
1124
  onChange: (e) => handleChange(e.target.value),
818
1125
  InputProps: {
819
- startAdornment: /* @__PURE__ */ React6.createElement(InputAdornment, { position: "start" }, /* @__PURE__ */ React6.createElement(SearchIcon, { fontSize: "tiny" }))
1126
+ startAdornment: /* @__PURE__ */ React8.createElement(InputAdornment, { position: "start" }, /* @__PURE__ */ React8.createElement(SearchIcon, { fontSize: "tiny" }))
820
1127
  }
821
1128
  }
822
1129
  )));
823
1130
  };
824
1131
 
825
1132
  // src/components/class-manager/class-manager-introduction.tsx
826
- import * as React7 from "react";
1133
+ import * as React9 from "react";
827
1134
  import { useState as useState2 } from "react";
828
1135
  import { useSuppressedMessage } from "@elementor/editor-current-user";
829
1136
  import { IntroductionModal } from "@elementor/editor-ui";
830
- import { Box as Box3, Image, Typography as Typography2 } from "@elementor/ui";
831
- import { __ as __6 } from "@wordpress/i18n";
1137
+ import { Box as Box4, Image, Typography as Typography3 } from "@elementor/ui";
1138
+ import { __ as __7 } from "@wordpress/i18n";
832
1139
  var MESSAGE_KEY = "global-class-manager";
833
1140
  var ClassManagerIntroduction = () => {
834
1141
  const [isMessageSuppressed, suppressMessage] = useSuppressedMessage(MESSAGE_KEY);
835
1142
  const [shouldShowIntroduction, setShouldShowIntroduction] = useState2(!isMessageSuppressed);
836
- return /* @__PURE__ */ React7.createElement(
1143
+ return /* @__PURE__ */ React9.createElement(
837
1144
  IntroductionModal,
838
1145
  {
839
1146
  open: shouldShowIntroduction,
840
- title: __6("Class Manager", "elementor"),
1147
+ title: __7("Class Manager", "elementor"),
841
1148
  handleClose: (shouldShowAgain) => {
842
1149
  if (!shouldShowAgain) {
843
1150
  suppressMessage();
@@ -845,7 +1152,7 @@ var ClassManagerIntroduction = () => {
845
1152
  setShouldShowIntroduction(false);
846
1153
  }
847
1154
  },
848
- /* @__PURE__ */ React7.createElement(
1155
+ /* @__PURE__ */ React9.createElement(
849
1156
  Image,
850
1157
  {
851
1158
  sx: { width: "100%", aspectRatio: "16 / 9" },
@@ -853,14 +1160,14 @@ var ClassManagerIntroduction = () => {
853
1160
  alt: ""
854
1161
  }
855
1162
  ),
856
- /* @__PURE__ */ React7.createElement(IntroductionContent, null)
1163
+ /* @__PURE__ */ React9.createElement(IntroductionContent, null)
857
1164
  );
858
1165
  };
859
1166
  var IntroductionContent = () => {
860
- return /* @__PURE__ */ React7.createElement(Box3, { p: 3 }, /* @__PURE__ */ React7.createElement(Typography2, { variant: "body2" }, __6(
1167
+ return /* @__PURE__ */ React9.createElement(Box4, { p: 3 }, /* @__PURE__ */ React9.createElement(Typography3, { variant: "body2" }, __7(
861
1168
  "The Class Manager lets you see all the classes you've created, plus adjust their priority, rename them, and delete unused classes to keep your CSS structured.",
862
1169
  "elementor"
863
- )), /* @__PURE__ */ React7.createElement("br", null), /* @__PURE__ */ React7.createElement(Typography2, { variant: "body2" }, __6(
1170
+ )), /* @__PURE__ */ React9.createElement("br", null), /* @__PURE__ */ React9.createElement(Typography3, { variant: "body2" }, __7(
864
1171
  "Remember, when editing an item within a specific class, any changes you make will apply across all elements in that class.",
865
1172
  "elementor"
866
1173
  )));
@@ -872,8 +1179,14 @@ import { __privateRunCommand as runCommand } from "@elementor/editor-v1-adapters
872
1179
  import { __dispatch as dispatch3 } from "@elementor/store";
873
1180
  var isDeleted = false;
874
1181
  var deleteClass = (id2) => {
875
- dispatch3(slice.actions.delete(id2));
876
- isDeleted = true;
1182
+ trackGlobalClasses({
1183
+ event: "classDeleted",
1184
+ classId: id2,
1185
+ runAction: () => {
1186
+ dispatch3(slice.actions.delete(id2));
1187
+ isDeleted = true;
1188
+ }
1189
+ });
877
1190
  };
878
1191
  var onDelete = async () => {
879
1192
  await reloadDocument();
@@ -892,16 +1205,16 @@ var reloadDocument = () => {
892
1205
  };
893
1206
 
894
1207
  // src/components/class-manager/flipped-color-swatch-icon.tsx
895
- import * as React8 from "react";
1208
+ import * as React10 from "react";
896
1209
  import { ColorSwatchIcon } from "@elementor/icons";
897
- var FlippedColorSwatchIcon = ({ sx, ...props }) => /* @__PURE__ */ React8.createElement(ColorSwatchIcon, { sx: { transform: "rotate(90deg)", ...sx }, ...props });
1210
+ var FlippedColorSwatchIcon = ({ sx, ...props }) => /* @__PURE__ */ React10.createElement(ColorSwatchIcon, { sx: { transform: "rotate(90deg)", ...sx }, ...props });
898
1211
 
899
1212
  // src/components/class-manager/global-classes-list.tsx
900
- import * as React15 from "react";
901
- import { useEffect, useMemo as useMemo3 } from "react";
1213
+ import * as React17 from "react";
1214
+ import { useEffect as useEffect2, useMemo as useMemo3 } from "react";
902
1215
  import { __useDispatch as useDispatch } from "@elementor/store";
903
- import { List, Stack as Stack7, styled as styled6, Typography as Typography7 } from "@elementor/ui";
904
- import { __ as __12 } from "@wordpress/i18n";
1216
+ import { List, Stack as Stack8, styled as styled6, Typography as Typography8 } from "@elementor/ui";
1217
+ import { __ as __13 } from "@wordpress/i18n";
905
1218
 
906
1219
  // src/hooks/use-ordered-classes.ts
907
1220
  import { __useSelector as useSelector3 } from "@elementor/store";
@@ -910,31 +1223,31 @@ var useOrderedClasses = () => {
910
1223
  };
911
1224
 
912
1225
  // src/components/class-manager/class-item.tsx
913
- import * as React13 from "react";
1226
+ import * as React15 from "react";
914
1227
  import { useRef, useState as useState4 } from "react";
915
1228
  import { validateStyleLabel } from "@elementor/editor-styles-repository";
916
- import { EditableField, EllipsisWithTooltip as EllipsisWithTooltip2, MenuListItem, useEditable, WarningInfotip } from "@elementor/editor-ui";
1229
+ import { EditableField, EllipsisWithTooltip as EllipsisWithTooltip3, MenuListItem, useEditable, WarningInfotip } from "@elementor/editor-ui";
917
1230
  import { DotsVerticalIcon } from "@elementor/icons";
918
1231
  import {
919
1232
  bindMenu,
920
1233
  bindTrigger as bindTrigger2,
921
- Box as Box7,
1234
+ Box as Box8,
922
1235
  IconButton as IconButton3,
923
1236
  ListItemButton,
924
1237
  Menu,
925
- Stack as Stack5,
1238
+ Stack as Stack6,
926
1239
  styled as styled5,
927
1240
  Tooltip as Tooltip5,
928
- Typography as Typography5,
1241
+ Typography as Typography6,
929
1242
  usePopupState as usePopupState3
930
1243
  } from "@elementor/ui";
931
- import { __ as __10 } from "@wordpress/i18n";
1244
+ import { __ as __11 } from "@wordpress/i18n";
932
1245
 
933
1246
  // src/components/css-class-usage/components/css-class-usage-popover.tsx
934
- import * as React9 from "react";
1247
+ import * as React11 from "react";
935
1248
  import { __useOpenDocumentInNewTab as useOpenDocumentInNewTab } from "@elementor/editor-documents";
936
1249
  import {
937
- EllipsisWithTooltip,
1250
+ EllipsisWithTooltip as EllipsisWithTooltip2,
938
1251
  PopoverBody as PopoverBody2,
939
1252
  PopoverHeader as PopoverHeader2,
940
1253
  PopoverMenuList
@@ -948,8 +1261,8 @@ import {
948
1261
  PopupTemplateIcon,
949
1262
  PostTypeIcon
950
1263
  } from "@elementor/icons";
951
- import { Box as Box4, Chip as Chip3, Divider as Divider2, Icon, MenuList as MenuList2, Stack as Stack4, styled as styled2, Tooltip as Tooltip3, Typography as Typography3 } from "@elementor/ui";
952
- import { __ as __7 } from "@wordpress/i18n";
1264
+ import { Box as Box5, Chip as Chip3, Divider as Divider3, Icon as Icon2, MenuList as MenuList2, Stack as Stack5, styled as styled2, Tooltip as Tooltip3, Typography as Typography4 } from "@elementor/ui";
1265
+ import { __ as __8 } from "@wordpress/i18n";
953
1266
 
954
1267
  // src/hooks/use-css-class-usage-by-id.ts
955
1268
  var EMPTY_CLASS_USAGE = {
@@ -965,24 +1278,24 @@ var useCssClassUsageByID = (id2) => {
965
1278
  // src/components/css-class-usage/components/css-class-usage-popover.tsx
966
1279
  var iconMapper = {
967
1280
  "wp-post": {
968
- label: __7("Post", "elementor"),
969
- icon: /* @__PURE__ */ React9.createElement(PostTypeIcon, { fontSize: "inherit" })
1281
+ label: __8("Post", "elementor"),
1282
+ icon: /* @__PURE__ */ React11.createElement(PostTypeIcon, { fontSize: "inherit" })
970
1283
  },
971
1284
  "wp-page": {
972
- label: __7("Page", "elementor"),
973
- icon: /* @__PURE__ */ React9.createElement(PagesIcon, { fontSize: "inherit" })
1285
+ label: __8("Page", "elementor"),
1286
+ icon: /* @__PURE__ */ React11.createElement(PagesIcon, { fontSize: "inherit" })
974
1287
  },
975
1288
  popup: {
976
- label: __7("Popup", "elementor"),
977
- icon: /* @__PURE__ */ React9.createElement(PopupTemplateIcon, { fontSize: "inherit" })
1289
+ label: __8("Popup", "elementor"),
1290
+ icon: /* @__PURE__ */ React11.createElement(PopupTemplateIcon, { fontSize: "inherit" })
978
1291
  },
979
1292
  header: {
980
- label: __7("Header", "elementor"),
981
- icon: /* @__PURE__ */ React9.createElement(HeaderTemplateIcon, { fontSize: "inherit" })
1293
+ label: __8("Header", "elementor"),
1294
+ icon: /* @__PURE__ */ React11.createElement(HeaderTemplateIcon, { fontSize: "inherit" })
982
1295
  },
983
1296
  footer: {
984
- label: __7("Footer", "elementor"),
985
- icon: /* @__PURE__ */ React9.createElement(FooterTemplateIcon, { fontSize: "inherit" })
1297
+ label: __8("Footer", "elementor"),
1298
+ icon: /* @__PURE__ */ React11.createElement(FooterTemplateIcon, { fontSize: "inherit" })
986
1299
  }
987
1300
  };
988
1301
  var CssClassUsagePopover = ({
@@ -1000,41 +1313,48 @@ var CssClassUsagePopover = ({
1000
1313
  docType: type
1001
1314
  })
1002
1315
  ) ?? [];
1003
- return /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(
1316
+ const handleSelect = (value) => {
1317
+ onNavigate(+value);
1318
+ trackGlobalClasses({
1319
+ event: "classUsageLocate",
1320
+ classId: cssClassID
1321
+ });
1322
+ };
1323
+ return /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(
1004
1324
  PopoverHeader2,
1005
1325
  {
1006
- icon: /* @__PURE__ */ React9.createElement(CurrentLocationIcon, { fontSize: "tiny" }),
1007
- title: /* @__PURE__ */ React9.createElement(Stack4, { flexDirection: "row", gap: 1, alignItems: "center" }, /* @__PURE__ */ React9.createElement(Box4, { "aria-label": "header-title" }, __7("Locator", "elementor")), /* @__PURE__ */ React9.createElement(Box4, null, /* @__PURE__ */ React9.createElement(Chip3, { sx: { lineHeight: 1 }, size: "tiny", label: classUsage.total }))),
1326
+ icon: /* @__PURE__ */ React11.createElement(CurrentLocationIcon, { fontSize: "tiny" }),
1327
+ title: /* @__PURE__ */ React11.createElement(Stack5, { flexDirection: "row", gap: 1, alignItems: "center" }, /* @__PURE__ */ React11.createElement(Box5, { "aria-label": "header-title" }, __8("Locator", "elementor")), /* @__PURE__ */ React11.createElement(Box5, null, /* @__PURE__ */ React11.createElement(Chip3, { sx: { lineHeight: 1 }, size: "tiny", label: classUsage.total }))),
1008
1328
  onClose
1009
1329
  }
1010
- ), /* @__PURE__ */ React9.createElement(Divider2, null), /* @__PURE__ */ React9.createElement(PopoverBody2, { width: 300 }, /* @__PURE__ */ React9.createElement(
1330
+ ), /* @__PURE__ */ React11.createElement(Divider3, null), /* @__PURE__ */ React11.createElement(PopoverBody2, { width: 300 }, /* @__PURE__ */ React11.createElement(
1011
1331
  PopoverMenuList,
1012
1332
  {
1013
- onSelect: (value) => onNavigate(+value),
1333
+ onSelect: handleSelect,
1014
1334
  items: cssClassUsageRecords,
1015
1335
  onClose: () => {
1016
1336
  },
1017
1337
  menuListTemplate: StyledCssClassUsageItem,
1018
- menuItemContentTemplate: (cssClassUsageRecord) => /* @__PURE__ */ React9.createElement(Stack4, { flexDirection: "row", flex: 1, alignItems: "center" }, /* @__PURE__ */ React9.createElement(Box4, { display: "flex", sx: { pr: 1 } }, /* @__PURE__ */ React9.createElement(
1338
+ menuItemContentTemplate: (cssClassUsageRecord) => /* @__PURE__ */ React11.createElement(Stack5, { flexDirection: "row", flex: 1, alignItems: "center" }, /* @__PURE__ */ React11.createElement(Box5, { display: "flex", sx: { pr: 1 } }, /* @__PURE__ */ React11.createElement(
1019
1339
  Tooltip3,
1020
1340
  {
1021
1341
  disableInteractive: true,
1022
1342
  title: iconMapper?.[cssClassUsageRecord.docType]?.label ?? cssClassUsageRecord.docType,
1023
1343
  placement: "top"
1024
1344
  },
1025
- /* @__PURE__ */ React9.createElement(Icon, { fontSize: "small" }, iconMapper?.[cssClassUsageRecord.docType]?.icon || /* @__PURE__ */ React9.createElement(PagesIcon, { fontSize: "inherit" }))
1026
- )), /* @__PURE__ */ React9.createElement(Box4, { sx: { pr: 0.5, maxWidth: "173px" }, display: "flex" }, /* @__PURE__ */ React9.createElement(
1027
- EllipsisWithTooltip,
1345
+ /* @__PURE__ */ React11.createElement(Icon2, { fontSize: "small" }, iconMapper?.[cssClassUsageRecord.docType]?.icon || /* @__PURE__ */ React11.createElement(PagesIcon, { fontSize: "inherit" }))
1346
+ )), /* @__PURE__ */ React11.createElement(Box5, { sx: { pr: 0.5, maxWidth: "173px" }, display: "flex" }, /* @__PURE__ */ React11.createElement(
1347
+ EllipsisWithTooltip2,
1028
1348
  {
1029
1349
  title: cssClassUsageRecord.label,
1030
- as: Typography3,
1350
+ as: Typography4,
1031
1351
  variant: "caption",
1032
1352
  maxWidth: "173px",
1033
1353
  sx: {
1034
1354
  lineHeight: 1
1035
1355
  }
1036
1356
  }
1037
- )), /* @__PURE__ */ React9.createElement(ExternalLinkIcon, { className: "hover-only-icon", fontSize: "tiny" }), /* @__PURE__ */ React9.createElement(
1357
+ )), /* @__PURE__ */ React11.createElement(ExternalLinkIcon, { className: "hover-only-icon", fontSize: "tiny" }), /* @__PURE__ */ React11.createElement(
1038
1358
  Chip3,
1039
1359
  {
1040
1360
  sx: {
@@ -1081,13 +1401,13 @@ var StyledCssClassUsageItem = styled2(MenuList2)(({ theme }) => ({
1081
1401
  }));
1082
1402
 
1083
1403
  // src/components/css-class-usage/components/css-class-usage-trigger.tsx
1084
- import * as React10 from "react";
1404
+ import * as React12 from "react";
1085
1405
  import { InfoAlert } from "@elementor/editor-ui";
1086
1406
  import { CurrentLocationIcon as CurrentLocationIcon2 } from "@elementor/icons";
1087
1407
  import {
1088
1408
  bindPopover as bindPopover2,
1089
1409
  bindTrigger,
1090
- Box as Box5,
1410
+ Box as Box6,
1091
1411
  IconButton as IconButton2,
1092
1412
  Infotip,
1093
1413
  Popover as Popover2,
@@ -1095,7 +1415,7 @@ import {
1095
1415
  Tooltip as Tooltip4,
1096
1416
  usePopupState as usePopupState2
1097
1417
  } from "@elementor/ui";
1098
- import { __ as __8 } from "@wordpress/i18n";
1418
+ import { __ as __9 } from "@wordpress/i18n";
1099
1419
  var CssClassUsageTrigger = ({ id: id2, onClick }) => {
1100
1420
  const {
1101
1421
  data: { total },
@@ -1106,21 +1426,33 @@ var CssClassUsageTrigger = ({ id: id2, onClick }) => {
1106
1426
  return null;
1107
1427
  }
1108
1428
  const WrapperComponent = total !== 0 ? TooltipWrapper : InfoAlertMessage;
1109
- return /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(Box5, { position: "relative" }, /* @__PURE__ */ React10.createElement(WrapperComponent, { total }, /* @__PURE__ */ React10.createElement(
1429
+ const handleMouseEnter = () => {
1430
+ trackGlobalClasses({
1431
+ event: "classUsageHovered",
1432
+ classId: id2,
1433
+ usage: total
1434
+ });
1435
+ };
1436
+ const handleClick = (e) => {
1437
+ if (total !== 0) {
1438
+ bindTrigger(cssClassUsagePopover).onClick(e);
1439
+ onClick(id2);
1440
+ trackGlobalClasses({
1441
+ event: "classUsageClicked",
1442
+ classId: id2
1443
+ });
1444
+ }
1445
+ };
1446
+ return /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(Box6, { position: "relative", onMouseEnter: handleMouseEnter }, /* @__PURE__ */ React12.createElement(WrapperComponent, { total }, /* @__PURE__ */ React12.createElement(
1110
1447
  CustomIconButton2,
1111
1448
  {
1112
1449
  disabled: total === 0,
1113
1450
  size: "tiny",
1114
1451
  ...bindTrigger(cssClassUsagePopover),
1115
- onClick: (e) => {
1116
- if (total !== 0) {
1117
- bindTrigger(cssClassUsagePopover).onClick(e);
1118
- onClick(id2);
1119
- }
1120
- }
1452
+ onClick: handleClick
1121
1453
  },
1122
- /* @__PURE__ */ React10.createElement(CurrentLocationIcon2, { fontSize: "tiny" })
1123
- ))), /* @__PURE__ */ React10.createElement(Box5, null, /* @__PURE__ */ React10.createElement(
1454
+ /* @__PURE__ */ React12.createElement(CurrentLocationIcon2, { fontSize: "tiny" })
1455
+ ))), /* @__PURE__ */ React12.createElement(Box6, null, /* @__PURE__ */ React12.createElement(
1124
1456
  Popover2,
1125
1457
  {
1126
1458
  anchorOrigin: {
@@ -1137,7 +1469,7 @@ var CssClassUsageTrigger = ({ id: id2, onClick }) => {
1137
1469
  onClick("");
1138
1470
  }
1139
1471
  },
1140
- /* @__PURE__ */ React10.createElement(
1472
+ /* @__PURE__ */ React12.createElement(
1141
1473
  CssClassUsagePopover,
1142
1474
  {
1143
1475
  onClose: cssClassUsagePopover.close,
@@ -1159,80 +1491,80 @@ var CustomIconButton2 = styled3(IconButton2)(({ theme }) => ({
1159
1491
  height: "22px",
1160
1492
  width: "22px"
1161
1493
  }));
1162
- var TooltipWrapper = ({ children, total }) => /* @__PURE__ */ React10.createElement(
1494
+ var TooltipWrapper = ({ children, total }) => /* @__PURE__ */ React12.createElement(
1163
1495
  Tooltip4,
1164
1496
  {
1165
1497
  disableInteractive: true,
1166
1498
  placement: "top",
1167
- title: `${__8("Show {{number}} {{locations}}", "elementor").replace("{{number}}", total.toString()).replace(
1499
+ title: `${__9("Show {{number}} {{locations}}", "elementor").replace("{{number}}", total.toString()).replace(
1168
1500
  "{{locations}}",
1169
- total === 1 ? __8("location", "elementor") : __8("locations", "elementor")
1501
+ total === 1 ? __9("location", "elementor") : __9("locations", "elementor")
1170
1502
  )}`
1171
1503
  },
1172
- /* @__PURE__ */ React10.createElement("span", null, children)
1504
+ /* @__PURE__ */ React12.createElement("span", null, children)
1173
1505
  );
1174
- var InfoAlertMessage = ({ children }) => /* @__PURE__ */ React10.createElement(
1506
+ var InfoAlertMessage = ({ children }) => /* @__PURE__ */ React12.createElement(
1175
1507
  Infotip,
1176
1508
  {
1177
1509
  disableInteractive: true,
1178
1510
  placement: "top",
1179
1511
  color: "secondary",
1180
- content: /* @__PURE__ */ React10.createElement(InfoAlert, { sx: { mt: 1 } }, __8("This class isn\u2019t being used yet.", "elementor"))
1512
+ content: /* @__PURE__ */ React12.createElement(InfoAlert, { sx: { mt: 1 } }, __9("This class isn\u2019t being used yet.", "elementor"))
1181
1513
  },
1182
- /* @__PURE__ */ React10.createElement("span", null, children)
1514
+ /* @__PURE__ */ React12.createElement("span", null, children)
1183
1515
  );
1184
1516
 
1185
1517
  // src/components/class-manager/delete-confirmation-dialog.tsx
1186
- import * as React11 from "react";
1518
+ import * as React13 from "react";
1187
1519
  import { createContext as createContext2, useContext as useContext2, useState as useState3 } from "react";
1188
1520
  import { AlertOctagonFilledIcon } from "@elementor/icons";
1189
1521
  import {
1190
- Button,
1522
+ Button as Button2,
1191
1523
  Dialog,
1192
- DialogActions,
1193
- DialogContent,
1524
+ DialogActions as DialogActions2,
1525
+ DialogContent as DialogContent2,
1194
1526
  DialogContentText,
1195
1527
  DialogTitle,
1196
- Typography as Typography4
1528
+ Typography as Typography5
1197
1529
  } from "@elementor/ui";
1198
- import { __ as __9 } from "@wordpress/i18n";
1530
+ import { __ as __10 } from "@wordpress/i18n";
1199
1531
  var context = createContext2(null);
1200
1532
  var DeleteConfirmationProvider = ({ children }) => {
1201
1533
  const [dialogProps, setDialogProps] = useState3(null);
1202
- const openDialog = (props) => {
1534
+ const openDialog2 = (props) => {
1203
1535
  setDialogProps(props);
1204
1536
  };
1205
- const closeDialog = () => {
1537
+ const closeDialog2 = () => {
1206
1538
  setDialogProps(null);
1207
1539
  };
1208
- return /* @__PURE__ */ React11.createElement(context.Provider, { value: { openDialog, closeDialog, dialogProps } }, children, !!dialogProps && /* @__PURE__ */ React11.createElement(DeleteConfirmationDialog, { ...dialogProps }));
1540
+ return /* @__PURE__ */ React13.createElement(context.Provider, { value: { openDialog: openDialog2, closeDialog: closeDialog2, dialogProps } }, children, !!dialogProps && /* @__PURE__ */ React13.createElement(DeleteConfirmationDialog, { ...dialogProps }));
1209
1541
  };
1210
1542
  var TITLE_ID = "delete-class-dialog";
1211
1543
  var DeleteConfirmationDialog = ({ label, id: id2 }) => {
1212
- const { closeDialog } = useDeleteConfirmation();
1544
+ const { closeDialog: closeDialog2 } = useDeleteConfirmation();
1213
1545
  const {
1214
1546
  data: { total, content }
1215
1547
  } = useCssClassUsageByID(id2);
1216
1548
  const onConfirm = () => {
1549
+ closeDialog2();
1217
1550
  deleteClass(id2);
1218
- closeDialog();
1219
1551
  };
1220
- const text = total && content.length ? __9(
1552
+ const text = total && content.length ? __10(
1221
1553
  "Will permanently remove it from your project and may affect the design across all elements using it. Used %1 times across %2 pages. This action cannot be undone.",
1222
1554
  "elementor"
1223
- ).replace("%1", total.toString()).replace("%2", content.length.toString()) : __9(
1555
+ ).replace("%1", total.toString()).replace("%2", content.length.toString()) : __10(
1224
1556
  "Will permanently remove it from your project and may affect the design across all elements using it. This action cannot be undone.",
1225
1557
  "elementor"
1226
1558
  );
1227
- return /* @__PURE__ */ React11.createElement(Dialog, { open: true, onClose: closeDialog, "aria-labelledby": TITLE_ID, maxWidth: "xs" }, /* @__PURE__ */ React11.createElement(DialogTitle, { id: TITLE_ID, display: "flex", alignItems: "center", gap: 1, sx: { lineHeight: 1 } }, /* @__PURE__ */ React11.createElement(AlertOctagonFilledIcon, { color: "error" }), __9("Delete this class?", "elementor")), /* @__PURE__ */ React11.createElement(DialogContent, null, /* @__PURE__ */ React11.createElement(DialogContentText, { variant: "body2", color: "textPrimary" }, __9("Deleting", "elementor"), /* @__PURE__ */ React11.createElement(Typography4, { variant: "subtitle2", component: "span" }, "\xA0", label, "\xA0"), text)), /* @__PURE__ */ React11.createElement(DialogActions, null, /* @__PURE__ */ React11.createElement(Button, { color: "secondary", onClick: closeDialog }, __9("Not now", "elementor")), /* @__PURE__ */ React11.createElement(
1228
- Button,
1559
+ return /* @__PURE__ */ React13.createElement(Dialog, { open: true, onClose: closeDialog2, "aria-labelledby": TITLE_ID, maxWidth: "xs" }, /* @__PURE__ */ React13.createElement(DialogTitle, { id: TITLE_ID, display: "flex", alignItems: "center", gap: 1, sx: { lineHeight: 1 } }, /* @__PURE__ */ React13.createElement(AlertOctagonFilledIcon, { color: "error" }), __10("Delete this class?", "elementor")), /* @__PURE__ */ React13.createElement(DialogContent2, null, /* @__PURE__ */ React13.createElement(DialogContentText, { variant: "body2", color: "textPrimary" }, __10("Deleting", "elementor"), /* @__PURE__ */ React13.createElement(Typography5, { variant: "subtitle2", component: "span" }, "\xA0", label, "\xA0"), text)), /* @__PURE__ */ React13.createElement(DialogActions2, null, /* @__PURE__ */ React13.createElement(Button2, { color: "secondary", onClick: closeDialog2 }, __10("Not now", "elementor")), /* @__PURE__ */ React13.createElement(
1560
+ Button2,
1229
1561
  {
1230
1562
  autoFocus: true,
1231
1563
  variant: "contained",
1232
1564
  color: "error",
1233
1565
  onClick: onConfirm
1234
1566
  },
1235
- __9("Delete", "elementor")
1567
+ __10("Delete", "elementor")
1236
1568
  )));
1237
1569
  };
1238
1570
  var useDeleteConfirmation = () => {
@@ -1244,18 +1576,18 @@ var useDeleteConfirmation = () => {
1244
1576
  };
1245
1577
 
1246
1578
  // src/components/class-manager/sortable.tsx
1247
- import * as React12 from "react";
1579
+ import * as React14 from "react";
1248
1580
  import { GripVerticalIcon } from "@elementor/icons";
1249
1581
  import {
1250
- Box as Box6,
1582
+ Box as Box7,
1251
1583
  styled as styled4,
1252
1584
  UnstableSortableItem,
1253
1585
  UnstableSortableProvider
1254
1586
  } from "@elementor/ui";
1255
- var SortableProvider = (props) => /* @__PURE__ */ React12.createElement(UnstableSortableProvider, { restrictAxis: true, variant: "static", dragPlaceholderStyle: { opacity: "1" }, ...props });
1256
- var SortableTrigger = (props) => /* @__PURE__ */ React12.createElement(StyledSortableTrigger, { ...props, role: "button", className: "class-item-sortable-trigger", "aria-label": "sort" }, /* @__PURE__ */ React12.createElement(GripVerticalIcon, { fontSize: "tiny" }));
1587
+ var SortableProvider = (props) => /* @__PURE__ */ React14.createElement(UnstableSortableProvider, { restrictAxis: true, variant: "static", dragPlaceholderStyle: { opacity: "1" }, ...props });
1588
+ var SortableTrigger = (props) => /* @__PURE__ */ React14.createElement(StyledSortableTrigger, { ...props, role: "button", className: "class-item-sortable-trigger", "aria-label": "sort" }, /* @__PURE__ */ React14.createElement(GripVerticalIcon, { fontSize: "tiny" }));
1257
1589
  var SortableItem = ({ children, id: id2, ...props }) => {
1258
- return /* @__PURE__ */ React12.createElement(
1590
+ return /* @__PURE__ */ React14.createElement(
1259
1591
  UnstableSortableItem,
1260
1592
  {
1261
1593
  ...props,
@@ -1271,8 +1603,8 @@ var SortableItem = ({ children, id: id2, ...props }) => {
1271
1603
  isDragOverlay,
1272
1604
  isDragPlaceholder
1273
1605
  }) => {
1274
- return /* @__PURE__ */ React12.createElement(
1275
- Box6,
1606
+ return /* @__PURE__ */ React14.createElement(
1607
+ Box7,
1276
1608
  {
1277
1609
  ...itemProps,
1278
1610
  style: itemStyle,
@@ -1290,7 +1622,7 @@ var SortableItem = ({ children, id: id2, ...props }) => {
1290
1622
  triggerStyle,
1291
1623
  isDragPlaceholder
1292
1624
  }),
1293
- showDropIndication && /* @__PURE__ */ React12.createElement(SortableItemIndicator, { style: dropIndicationStyle })
1625
+ showDropIndication && /* @__PURE__ */ React14.createElement(SortableItemIndicator, { style: dropIndicationStyle })
1294
1626
  );
1295
1627
  }
1296
1628
  }
@@ -1303,7 +1635,7 @@ var StyledSortableTrigger = styled4("div")(({ theme }) => ({
1303
1635
  transform: `translate( -${theme.spacing(1.5)}, -50% )`,
1304
1636
  color: theme.palette.action.active
1305
1637
  }));
1306
- var SortableItemIndicator = styled4(Box6)`
1638
+ var SortableItemIndicator = styled4(Box7)`
1307
1639
  width: 100%;
1308
1640
  height: 1px;
1309
1641
  background-color: ${({ theme }) => theme.palette.text.primary};
@@ -1332,13 +1664,13 @@ var ClassItem = ({
1332
1664
  validation: validateLabel
1333
1665
  });
1334
1666
  const [selectedCssUsage, setSelectedCssUsage] = useState4("");
1335
- const { openDialog } = useDeleteConfirmation();
1667
+ const { openDialog: openDialog2 } = useDeleteConfirmation();
1336
1668
  const popupState = usePopupState3({
1337
1669
  variant: "popover",
1338
1670
  disableAutoFocus: true
1339
1671
  });
1340
1672
  const isSelected = (selectedCssUsage === id2 || selected || popupState.isOpen) && !disabled;
1341
- return /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(Stack5, { p: 0 }, /* @__PURE__ */ React13.createElement(
1673
+ return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(Stack6, { p: 0 }, /* @__PURE__ */ React15.createElement(
1342
1674
  WarningInfotip,
1343
1675
  {
1344
1676
  open: Boolean(error),
@@ -1347,7 +1679,7 @@ var ClassItem = ({
1347
1679
  width: itemRef.current?.getBoundingClientRect().width,
1348
1680
  offset: [0, -15]
1349
1681
  },
1350
- /* @__PURE__ */ React13.createElement(
1682
+ /* @__PURE__ */ React15.createElement(
1351
1683
  StyledListItemButton,
1352
1684
  {
1353
1685
  ref: itemRef,
@@ -1361,28 +1693,28 @@ var ClassItem = ({
1361
1693
  disabled,
1362
1694
  focusVisibleClassName: "visible-class-item"
1363
1695
  },
1364
- /* @__PURE__ */ React13.createElement(SortableTrigger, { ...sortableTriggerProps }),
1365
- /* @__PURE__ */ React13.createElement(Indicator, { isActive: isEditing, isError: !!error }, isEditing ? /* @__PURE__ */ React13.createElement(
1696
+ /* @__PURE__ */ React15.createElement(SortableTrigger, { ...sortableTriggerProps }),
1697
+ /* @__PURE__ */ React15.createElement(Indicator, { isActive: isEditing, isError: !!error }, isEditing ? /* @__PURE__ */ React15.createElement(
1366
1698
  EditableField,
1367
1699
  {
1368
1700
  ref: editableRef,
1369
- as: Typography5,
1701
+ as: Typography6,
1370
1702
  variant: "caption",
1371
1703
  ...getEditableProps()
1372
1704
  }
1373
- ) : /* @__PURE__ */ React13.createElement(EllipsisWithTooltip2, { title: label, as: Typography5, variant: "caption" })),
1374
- /* @__PURE__ */ React13.createElement(Box7, { className: "class-item-locator" }, /* @__PURE__ */ React13.createElement(CssClassUsageTrigger, { id: id2, onClick: setSelectedCssUsage })),
1375
- /* @__PURE__ */ React13.createElement(
1705
+ ) : /* @__PURE__ */ React15.createElement(EllipsisWithTooltip3, { title: label, as: Typography6, variant: "caption" })),
1706
+ /* @__PURE__ */ React15.createElement(Box8, { className: "class-item-locator" }, /* @__PURE__ */ React15.createElement(CssClassUsageTrigger, { id: id2, onClick: setSelectedCssUsage })),
1707
+ /* @__PURE__ */ React15.createElement(
1376
1708
  Tooltip5,
1377
1709
  {
1378
1710
  placement: "top",
1379
1711
  className: "class-item-more-actions",
1380
- title: __10("More actions", "elementor")
1712
+ title: __11("More actions", "elementor")
1381
1713
  },
1382
- /* @__PURE__ */ React13.createElement(IconButton3, { size: "tiny", ...bindTrigger2(popupState), "aria-label": "More actions" }, /* @__PURE__ */ React13.createElement(DotsVerticalIcon, { fontSize: "tiny" }))
1714
+ /* @__PURE__ */ React15.createElement(IconButton3, { size: "tiny", ...bindTrigger2(popupState), "aria-label": "More actions" }, /* @__PURE__ */ React15.createElement(DotsVerticalIcon, { fontSize: "tiny" }))
1383
1715
  )
1384
1716
  )
1385
- )), /* @__PURE__ */ React13.createElement(
1717
+ )), /* @__PURE__ */ React15.createElement(
1386
1718
  Menu,
1387
1719
  {
1388
1720
  ...bindMenu(popupState),
@@ -1395,7 +1727,7 @@ var ClassItem = ({
1395
1727
  horizontal: "right"
1396
1728
  }
1397
1729
  },
1398
- /* @__PURE__ */ React13.createElement(
1730
+ /* @__PURE__ */ React15.createElement(
1399
1731
  MenuListItem,
1400
1732
  {
1401
1733
  sx: { minWidth: "160px" },
@@ -1404,17 +1736,17 @@ var ClassItem = ({
1404
1736
  openEditMode();
1405
1737
  }
1406
1738
  },
1407
- /* @__PURE__ */ React13.createElement(Typography5, { variant: "caption", sx: { color: "text.primary" } }, __10("Rename", "elementor"))
1739
+ /* @__PURE__ */ React15.createElement(Typography6, { variant: "caption", sx: { color: "text.primary" } }, __11("Rename", "elementor"))
1408
1740
  ),
1409
- /* @__PURE__ */ React13.createElement(
1741
+ /* @__PURE__ */ React15.createElement(
1410
1742
  MenuListItem,
1411
1743
  {
1412
1744
  onClick: () => {
1413
1745
  popupState.close();
1414
- openDialog({ id: id2, label });
1746
+ openDialog2({ id: id2, label });
1415
1747
  }
1416
1748
  },
1417
- /* @__PURE__ */ React13.createElement(Typography5, { variant: "caption", sx: { color: "error.light" } }, __10("Delete", "elementor"))
1749
+ /* @__PURE__ */ React15.createElement(Typography6, { variant: "caption", sx: { color: "error.light" } }, __11("Delete", "elementor"))
1418
1750
  )
1419
1751
  ));
1420
1752
  };
@@ -1447,7 +1779,7 @@ var StyledListItemButton = styled5(ListItemButton, {
1447
1779
  }
1448
1780
  `
1449
1781
  );
1450
- var Indicator = styled5(Box7, {
1782
+ var Indicator = styled5(Box8, {
1451
1783
  shouldForwardProp: (prop) => !["isActive", "isError"].includes(prop)
1452
1784
  })(({ theme, isActive, isError }) => ({
1453
1785
  display: "flex",
@@ -1477,10 +1809,10 @@ var validateLabel = (newLabel) => {
1477
1809
  };
1478
1810
 
1479
1811
  // src/components/class-manager/not-found.tsx
1480
- import * as React14 from "react";
1812
+ import * as React16 from "react";
1481
1813
  import { ColorSwatchIcon as ColorSwatchIcon2, PhotoIcon } from "@elementor/icons";
1482
- import { Box as Box8, Link, Stack as Stack6, Typography as Typography6 } from "@elementor/ui";
1483
- import { __ as __11 } from "@wordpress/i18n";
1814
+ import { Box as Box9, Link, Stack as Stack7, Typography as Typography7 } from "@elementor/ui";
1815
+ import { __ as __12 } from "@wordpress/i18n";
1484
1816
  var getNotFoundType = (searchValue, filters, filteredClasses) => {
1485
1817
  const searchNotFound = filteredClasses.length <= 0 && searchValue.length > 1;
1486
1818
  const filterNotFound = filters && filters.length === 0;
@@ -1498,19 +1830,19 @@ var getNotFoundType = (searchValue, filters, filteredClasses) => {
1498
1830
  };
1499
1831
  var notFound = {
1500
1832
  filterAndSearch: {
1501
- mainText: __11("Sorry, nothing matched.", "elementor"),
1502
- sceneryText: __11("Try something else.", "elementor"),
1503
- icon: /* @__PURE__ */ React14.createElement(PhotoIcon, { color: "inherit", fontSize: "large" })
1833
+ mainText: __12("Sorry, nothing matched.", "elementor"),
1834
+ sceneryText: __12("Try something else.", "elementor"),
1835
+ icon: /* @__PURE__ */ React16.createElement(PhotoIcon, { color: "inherit", fontSize: "large" })
1504
1836
  },
1505
1837
  search: {
1506
- mainText: __11("Sorry, nothing matched", "elementor"),
1507
- sceneryText: __11("Clear your input and try something else.", "elementor"),
1508
- icon: /* @__PURE__ */ React14.createElement(PhotoIcon, { color: "inherit", fontSize: "large" })
1838
+ mainText: __12("Sorry, nothing matched", "elementor"),
1839
+ sceneryText: __12("Clear your input and try something else.", "elementor"),
1840
+ icon: /* @__PURE__ */ React16.createElement(PhotoIcon, { color: "inherit", fontSize: "large" })
1509
1841
  },
1510
1842
  filter: {
1511
- mainText: __11("Sorry, nothing matched that search.", "elementor"),
1512
- sceneryText: __11("Clear the filters and try something else.", "elementor"),
1513
- icon: /* @__PURE__ */ React14.createElement(ColorSwatchIcon2, { color: "inherit", fontSize: "large" })
1843
+ mainText: __12("Sorry, nothing matched that search.", "elementor"),
1844
+ sceneryText: __12("Clear the filters and try something else.", "elementor"),
1845
+ icon: /* @__PURE__ */ React16.createElement(ColorSwatchIcon2, { color: "inherit", fontSize: "large" })
1514
1846
  }
1515
1847
  };
1516
1848
  var NotFound = ({ notFoundType }) => {
@@ -1520,11 +1852,11 @@ var NotFound = ({ notFoundType }) => {
1520
1852
  } = useSearchAndFilters();
1521
1853
  switch (notFoundType) {
1522
1854
  case "filter":
1523
- return /* @__PURE__ */ React14.createElement(NotFoundLayout, { ...notFound.filter, onClear: onClearFilter });
1855
+ return /* @__PURE__ */ React16.createElement(NotFoundLayout, { ...notFound.filter, onClear: onClearFilter });
1524
1856
  case "search":
1525
- return /* @__PURE__ */ React14.createElement(NotFoundLayout, { ...notFound.search, searchValue: inputValue, onClear: onClearSearch });
1857
+ return /* @__PURE__ */ React16.createElement(NotFoundLayout, { ...notFound.search, searchValue: inputValue, onClear: onClearSearch });
1526
1858
  case "filterAndSearch":
1527
- return /* @__PURE__ */ React14.createElement(
1859
+ return /* @__PURE__ */ React16.createElement(
1528
1860
  NotFoundLayout,
1529
1861
  {
1530
1862
  ...notFound.filterAndSearch,
@@ -1536,8 +1868,8 @@ var NotFound = ({ notFoundType }) => {
1536
1868
  );
1537
1869
  }
1538
1870
  };
1539
- var NotFoundLayout = ({ onClear, searchValue, mainText, sceneryText, icon }) => /* @__PURE__ */ React14.createElement(
1540
- Stack6,
1871
+ var NotFoundLayout = ({ onClear, searchValue, mainText, sceneryText, icon }) => /* @__PURE__ */ React16.createElement(
1872
+ Stack7,
1541
1873
  {
1542
1874
  color: "text.secondary",
1543
1875
  pt: 5,
@@ -1547,16 +1879,16 @@ var NotFoundLayout = ({ onClear, searchValue, mainText, sceneryText, icon }) =>
1547
1879
  justifySelf: "center"
1548
1880
  },
1549
1881
  icon,
1550
- /* @__PURE__ */ React14.createElement(
1551
- Box8,
1882
+ /* @__PURE__ */ React16.createElement(
1883
+ Box9,
1552
1884
  {
1553
1885
  sx: {
1554
1886
  width: "100%"
1555
1887
  }
1556
1888
  },
1557
- /* @__PURE__ */ React14.createElement(Typography6, { align: "center", variant: "subtitle2", color: "inherit" }, mainText),
1558
- searchValue && /* @__PURE__ */ React14.createElement(
1559
- Typography6,
1889
+ /* @__PURE__ */ React16.createElement(Typography7, { align: "center", variant: "subtitle2", color: "inherit" }, mainText),
1890
+ searchValue && /* @__PURE__ */ React16.createElement(
1891
+ Typography7,
1560
1892
  {
1561
1893
  variant: "subtitle2",
1562
1894
  color: "inherit",
@@ -1566,8 +1898,8 @@ var NotFoundLayout = ({ onClear, searchValue, mainText, sceneryText, icon }) =>
1566
1898
  justifyContent: "center"
1567
1899
  }
1568
1900
  },
1569
- /* @__PURE__ */ React14.createElement("span", null, "\u201C"),
1570
- /* @__PURE__ */ React14.createElement(
1901
+ /* @__PURE__ */ React16.createElement("span", null, "\u201C"),
1902
+ /* @__PURE__ */ React16.createElement(
1571
1903
  "span",
1572
1904
  {
1573
1905
  style: {
@@ -1578,11 +1910,11 @@ var NotFoundLayout = ({ onClear, searchValue, mainText, sceneryText, icon }) =>
1578
1910
  },
1579
1911
  searchValue
1580
1912
  ),
1581
- /* @__PURE__ */ React14.createElement("span", null, "\u201D.")
1913
+ /* @__PURE__ */ React16.createElement("span", null, "\u201D.")
1582
1914
  )
1583
1915
  ),
1584
- /* @__PURE__ */ React14.createElement(Typography6, { align: "center", variant: "caption", color: "inherit" }, sceneryText),
1585
- /* @__PURE__ */ React14.createElement(Typography6, { align: "center", variant: "caption", color: "inherit" }, /* @__PURE__ */ React14.createElement(Link, { color: "secondary", variant: "caption", component: "button", onClick: onClear }, __11("Clear & try again", "elementor")))
1916
+ /* @__PURE__ */ React16.createElement(Typography7, { align: "center", variant: "caption", color: "inherit" }, sceneryText),
1917
+ /* @__PURE__ */ React16.createElement(Typography7, { align: "center", variant: "caption", color: "inherit" }, /* @__PURE__ */ React16.createElement(Link, { color: "secondary", variant: "caption", component: "button", onClick: onClear }, __12("Clear & try again", "elementor")))
1586
1918
  );
1587
1919
 
1588
1920
  // src/components/class-manager/global-classes-list.tsx
@@ -1593,9 +1925,11 @@ var GlobalClassesList = ({ disabled }) => {
1593
1925
  const cssClasses = useOrderedClasses();
1594
1926
  const dispatch5 = useDispatch();
1595
1927
  const filters = useFilters();
1596
- const [classesOrder, reorderClasses] = useReorder();
1928
+ const [draggedItemId, setDraggedItemId] = React17.useState(null);
1929
+ const draggedItemLabel = cssClasses.find((cssClass) => cssClass.id === draggedItemId)?.label ?? "";
1930
+ const [classesOrder, reorderClasses] = useReorder(draggedItemId, setDraggedItemId, draggedItemLabel ?? "");
1597
1931
  const filteredCssClasses = useFilteredCssClasses();
1598
- useEffect(() => {
1932
+ useEffect2(() => {
1599
1933
  const handler = (event) => {
1600
1934
  if (event.key === "z" && (event.ctrlKey || event.metaKey)) {
1601
1935
  event.stopImmediatePropagation();
@@ -1613,58 +1947,81 @@ var GlobalClassesList = ({ disabled }) => {
1613
1947
  return () => window.removeEventListener("keydown", handler);
1614
1948
  }, [dispatch5]);
1615
1949
  if (!cssClasses?.length) {
1616
- return /* @__PURE__ */ React15.createElement(EmptyState, null);
1950
+ return /* @__PURE__ */ React17.createElement(EmptyState, null);
1617
1951
  }
1618
1952
  const notFoundType = getNotFoundType(searchValue, filters, filteredCssClasses);
1619
1953
  if (notFoundType) {
1620
- return /* @__PURE__ */ React15.createElement(NotFound, { notFoundType });
1954
+ return /* @__PURE__ */ React17.createElement(NotFound, { notFoundType });
1621
1955
  }
1622
1956
  const isFiltersApplied = filters?.length || searchValue;
1623
1957
  const allowSorting = filteredCssClasses.length > 1 && !isFiltersApplied;
1624
- return /* @__PURE__ */ React15.createElement(DeleteConfirmationProvider, null, /* @__PURE__ */ React15.createElement(List, { sx: { display: "flex", flexDirection: "column", gap: 0.5 } }, /* @__PURE__ */ React15.createElement(
1958
+ return /* @__PURE__ */ React17.createElement(DeleteConfirmationProvider, null, /* @__PURE__ */ React17.createElement(List, { sx: { display: "flex", flexDirection: "column", gap: 0.5 } }, /* @__PURE__ */ React17.createElement(
1625
1959
  SortableProvider,
1626
1960
  {
1627
1961
  value: classesOrder,
1628
1962
  onChange: reorderClasses,
1629
1963
  disableDragOverlay: !allowSorting
1630
1964
  },
1631
- filteredCssClasses?.map(({ id: id2, label }) => /* @__PURE__ */ React15.createElement(SortableItem, { key: id2, id: id2 }, ({ isDragged, isDragPlaceholder, triggerProps, triggerStyle }) => /* @__PURE__ */ React15.createElement(
1632
- ClassItem,
1633
- {
1634
- id: id2,
1635
- label,
1636
- renameClass: (newLabel) => {
1637
- dispatch5(
1638
- slice.actions.update({
1639
- style: {
1640
- id: id2,
1641
- label: newLabel
1642
- }
1643
- })
1644
- );
1645
- },
1646
- selected: isDragged,
1647
- disabled: disabled || isDragPlaceholder,
1648
- sortableTriggerProps: { ...triggerProps, style: triggerStyle },
1649
- showSortIndicator: allowSorting
1965
+ filteredCssClasses?.map(({ id: id2, label }) => /* @__PURE__ */ React17.createElement(SortableItem, { key: id2, id: id2 }, ({ isDragged, isDragPlaceholder, triggerProps, triggerStyle }) => {
1966
+ if (isDragged && !draggedItemId) {
1967
+ setDraggedItemId(id2);
1650
1968
  }
1651
- )))
1969
+ return /* @__PURE__ */ React17.createElement(
1970
+ ClassItem,
1971
+ {
1972
+ id: id2,
1973
+ label,
1974
+ renameClass: (newLabel) => {
1975
+ trackGlobalClasses({
1976
+ event: "classRenamed",
1977
+ classId: id2,
1978
+ oldValue: label,
1979
+ newValue: newLabel,
1980
+ source: "class-manager"
1981
+ });
1982
+ dispatch5(
1983
+ slice.actions.update({
1984
+ style: {
1985
+ id: id2,
1986
+ label: newLabel
1987
+ }
1988
+ })
1989
+ );
1990
+ },
1991
+ selected: isDragged,
1992
+ disabled: disabled || isDragPlaceholder,
1993
+ sortableTriggerProps: {
1994
+ ...triggerProps,
1995
+ style: triggerStyle
1996
+ },
1997
+ showSortIndicator: allowSorting
1998
+ }
1999
+ );
2000
+ }))
1652
2001
  )));
1653
2002
  };
1654
- var EmptyState = () => /* @__PURE__ */ React15.createElement(Stack7, { alignItems: "center", gap: 1.5, pt: 10, px: 0.5, maxWidth: "260px", margin: "auto" }, /* @__PURE__ */ React15.createElement(FlippedColorSwatchIcon, { fontSize: "large" }), /* @__PURE__ */ React15.createElement(StyledHeader, { variant: "subtitle2", component: "h2", color: "text.secondary" }, __12("There are no global classes yet.", "elementor")), /* @__PURE__ */ React15.createElement(Typography7, { align: "center", variant: "caption", color: "text.secondary" }, __12(
2003
+ var EmptyState = () => /* @__PURE__ */ React17.createElement(Stack8, { alignItems: "center", gap: 1.5, pt: 10, px: 0.5, maxWidth: "260px", margin: "auto" }, /* @__PURE__ */ React17.createElement(FlippedColorSwatchIcon, { fontSize: "large" }), /* @__PURE__ */ React17.createElement(StyledHeader, { variant: "subtitle2", component: "h2", color: "text.secondary" }, __13("There are no global classes yet.", "elementor")), /* @__PURE__ */ React17.createElement(Typography8, { align: "center", variant: "caption", color: "text.secondary" }, __13(
1655
2004
  "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.",
1656
2005
  "elementor"
1657
2006
  )));
1658
- var StyledHeader = styled6(Typography7)(({ theme, variant }) => ({
2007
+ var StyledHeader = styled6(Typography8)(({ theme, variant }) => ({
1659
2008
  "&.MuiTypography-root": {
1660
2009
  ...theme.typography[variant]
1661
2010
  }
1662
2011
  }));
1663
- var useReorder = () => {
2012
+ var useReorder = (draggedItemId, setDraggedItemId, draggedItemLabel) => {
1664
2013
  const dispatch5 = useDispatch();
1665
2014
  const order = useClassesOrder();
1666
2015
  const reorder = (newIds) => {
1667
2016
  dispatch5(slice.actions.setOrder(newIds));
2017
+ if (draggedItemId) {
2018
+ trackGlobalClasses({
2019
+ event: "classManagerReorder",
2020
+ classId: draggedItemId,
2021
+ classTitle: draggedItemLabel
2022
+ });
2023
+ setDraggedItemId(null);
2024
+ }
1668
2025
  };
1669
2026
  return [order, reorder];
1670
2027
  };
@@ -1705,44 +2062,6 @@ function unblockPanelInteractions() {
1705
2062
  extendedWindow.$e?.components?.get?.("panel")?.unblockUserInteractions?.();
1706
2063
  }
1707
2064
 
1708
- // src/components/class-manager/save-changes-dialog.tsx
1709
- import * as React16 from "react";
1710
- import { useState as useState5 } from "react";
1711
- import { AlertTriangleFilledIcon } from "@elementor/icons";
1712
- import {
1713
- Button as Button2,
1714
- Dialog as Dialog2,
1715
- DialogActions as DialogActions2,
1716
- DialogContent as DialogContent2,
1717
- DialogContentText as DialogContentText2,
1718
- DialogTitle as DialogTitle2
1719
- } from "@elementor/ui";
1720
- var TITLE_ID2 = "save-changes-dialog";
1721
- var SaveChangesDialog = ({ children, onClose }) => /* @__PURE__ */ React16.createElement(Dialog2, { open: true, onClose, "aria-labelledby": TITLE_ID2, maxWidth: "xs" }, children);
1722
- var SaveChangesDialogTitle = ({ children }) => /* @__PURE__ */ React16.createElement(DialogTitle2, { id: TITLE_ID2, display: "flex", alignItems: "center", gap: 1, sx: { lineHeight: 1 } }, /* @__PURE__ */ React16.createElement(AlertTriangleFilledIcon, { color: "secondary" }), children);
1723
- var SaveChangesDialogContent = ({ children }) => /* @__PURE__ */ React16.createElement(DialogContent2, null, children);
1724
- var SaveChangesDialogContentText = (props) => /* @__PURE__ */ React16.createElement(DialogContentText2, { variant: "body2", color: "textPrimary", display: "flex", flexDirection: "column", ...props });
1725
- var SaveChangesDialogActions = ({ actions }) => {
1726
- const [isConfirming, setIsConfirming] = useState5(false);
1727
- const { cancel, confirm, discard } = actions;
1728
- const onConfirm = async () => {
1729
- setIsConfirming(true);
1730
- await confirm.action();
1731
- setIsConfirming(false);
1732
- };
1733
- return /* @__PURE__ */ React16.createElement(DialogActions2, null, cancel && /* @__PURE__ */ React16.createElement(Button2, { variant: "text", color: "secondary", onClick: cancel.action }, cancel.label), discard && /* @__PURE__ */ React16.createElement(Button2, { variant: "text", color: "secondary", onClick: discard.action }, discard.label), /* @__PURE__ */ React16.createElement(Button2, { variant: "contained", color: "secondary", onClick: onConfirm, loading: isConfirming }, confirm.label));
1734
- };
1735
- SaveChangesDialog.Title = SaveChangesDialogTitle;
1736
- SaveChangesDialog.Content = SaveChangesDialogContent;
1737
- SaveChangesDialog.ContentText = SaveChangesDialogContentText;
1738
- SaveChangesDialog.Actions = SaveChangesDialogActions;
1739
- var useDialog = () => {
1740
- const [isOpen, setIsOpen] = useState5(false);
1741
- const open = () => setIsOpen(true);
1742
- const close = () => setIsOpen(false);
1743
- return { isOpen, open, close };
1744
- };
1745
-
1746
2065
  // src/components/class-manager/class-manager-panel.tsx
1747
2066
  var id = "global-classes-manager";
1748
2067
  var { panel, usePanelActions } = createPanel({
@@ -1756,7 +2075,8 @@ var { panel, usePanelActions } = createPanel({
1756
2075
  onClose: () => {
1757
2076
  changeEditMode("edit");
1758
2077
  unblockPanelInteractions();
1759
- }
2078
+ },
2079
+ isOpenPreviousElement: true
1760
2080
  });
1761
2081
  function ClassManagerPanel() {
1762
2082
  const isDirty2 = useDirtyState();
@@ -1768,7 +2088,7 @@ function ClassManagerPanel() {
1768
2088
  closeSaveChangesDialog();
1769
2089
  };
1770
2090
  usePreventUnload();
1771
- return /* @__PURE__ */ React17.createElement(ThemeProvider, null, /* @__PURE__ */ React17.createElement(ErrorBoundary, { fallback: /* @__PURE__ */ React17.createElement(ErrorBoundaryFallback, null) }, /* @__PURE__ */ React17.createElement(Panel, null, /* @__PURE__ */ React17.createElement(SearchAndFilterProvider, null, /* @__PURE__ */ React17.createElement(PanelHeader, null, /* @__PURE__ */ React17.createElement(Stack8, { p: 1, pl: 2, width: "100%", direction: "row", alignItems: "center" }, /* @__PURE__ */ React17.createElement(Stack8, { width: "100%", direction: "row", gap: 1 }, /* @__PURE__ */ React17.createElement(PanelHeaderTitle, { sx: { display: "flex", alignItems: "center", gap: 0.5 } }, /* @__PURE__ */ React17.createElement(FlippedColorSwatchIcon, { fontSize: "inherit" }), __13("Class Manager", "elementor")), /* @__PURE__ */ React17.createElement(TotalCssClassCounter, null)), /* @__PURE__ */ React17.createElement(
2091
+ return /* @__PURE__ */ React18.createElement(ThemeProvider, null, /* @__PURE__ */ React18.createElement(ErrorBoundary, { fallback: /* @__PURE__ */ React18.createElement(ErrorBoundaryFallback, null) }, /* @__PURE__ */ React18.createElement(Panel, null, /* @__PURE__ */ React18.createElement(SearchAndFilterProvider, null, /* @__PURE__ */ React18.createElement(PanelHeader, null, /* @__PURE__ */ React18.createElement(Stack9, { p: 1, pl: 2, width: "100%", direction: "row", alignItems: "center" }, /* @__PURE__ */ React18.createElement(Stack9, { width: "100%", direction: "row", gap: 1 }, /* @__PURE__ */ React18.createElement(PanelHeaderTitle, { sx: { display: "flex", alignItems: "center", gap: 0.5 } }, /* @__PURE__ */ React18.createElement(FlippedColorSwatchIcon, { fontSize: "inherit" }), __14("Class Manager", "elementor")), /* @__PURE__ */ React18.createElement(TotalCssClassCounter, null)), /* @__PURE__ */ React18.createElement(
1772
2092
  CloseButton,
1773
2093
  {
1774
2094
  sx: { marginLeft: "auto" },
@@ -1781,7 +2101,7 @@ function ClassManagerPanel() {
1781
2101
  closePanel();
1782
2102
  }
1783
2103
  }
1784
- ))), /* @__PURE__ */ React17.createElement(
2104
+ ))), /* @__PURE__ */ React18.createElement(
1785
2105
  PanelBody,
1786
2106
  {
1787
2107
  sx: {
@@ -1790,10 +2110,10 @@ function ClassManagerPanel() {
1790
2110
  height: "100%"
1791
2111
  }
1792
2112
  },
1793
- /* @__PURE__ */ React17.createElement(Box9, { px: 2, pb: 1 }, /* @__PURE__ */ React17.createElement(Stack8, { direction: "row", justifyContent: "spaceBetween", gap: 0.5, sx: { pb: 0.5 } }, /* @__PURE__ */ React17.createElement(Box9, { sx: { flexGrow: 1 } }, /* @__PURE__ */ React17.createElement(ClassManagerSearch, null)), /* @__PURE__ */ React17.createElement(CssClassFilter, null)), /* @__PURE__ */ React17.createElement(ActiveFilters, null)),
1794
- /* @__PURE__ */ React17.createElement(Divider3, null),
1795
- /* @__PURE__ */ React17.createElement(
1796
- Box9,
2113
+ /* @__PURE__ */ React18.createElement(Box10, { px: 2, pb: 1 }, /* @__PURE__ */ React18.createElement(Stack9, { direction: "row", justifyContent: "spaceBetween", gap: 0.5, sx: { pb: 0.5 } }, /* @__PURE__ */ React18.createElement(Box10, { sx: { flexGrow: 1 } }, /* @__PURE__ */ React18.createElement(ClassManagerSearch, null)), /* @__PURE__ */ React18.createElement(CssClassFilter, null)), /* @__PURE__ */ React18.createElement(ActiveFilters, null)),
2114
+ /* @__PURE__ */ React18.createElement(Divider4, null),
2115
+ /* @__PURE__ */ React18.createElement(
2116
+ Box10,
1797
2117
  {
1798
2118
  px: 2,
1799
2119
  sx: {
@@ -1801,9 +2121,9 @@ function ClassManagerPanel() {
1801
2121
  overflowY: "auto"
1802
2122
  }
1803
2123
  },
1804
- /* @__PURE__ */ React17.createElement(GlobalClassesList, { disabled: isPublishing })
2124
+ /* @__PURE__ */ React18.createElement(GlobalClassesList, { disabled: isPublishing })
1805
2125
  )
1806
- ), /* @__PURE__ */ React17.createElement(PanelFooter, null, /* @__PURE__ */ React17.createElement(
2126
+ ), /* @__PURE__ */ React18.createElement(PanelFooter, null, /* @__PURE__ */ React18.createElement(
1807
2127
  Button3,
1808
2128
  {
1809
2129
  fullWidth: true,
@@ -1814,19 +2134,19 @@ function ClassManagerPanel() {
1814
2134
  disabled: !isDirty2,
1815
2135
  loading: isPublishing
1816
2136
  },
1817
- __13("Save changes", "elementor")
1818
- ))))), /* @__PURE__ */ React17.createElement(ClassManagerIntroduction, null), isSaveChangesDialogOpen && /* @__PURE__ */ React17.createElement(SaveChangesDialog, null, /* @__PURE__ */ React17.createElement(DialogHeader, { onClose: closeSaveChangesDialog, logo: false }, /* @__PURE__ */ React17.createElement(SaveChangesDialog.Title, null, __13("You have unsaved changes", "elementor"))), /* @__PURE__ */ React17.createElement(SaveChangesDialog.Content, null, /* @__PURE__ */ React17.createElement(SaveChangesDialog.ContentText, null, __13("You have unsaved changes in the Class Manager.", "elementor")), /* @__PURE__ */ React17.createElement(SaveChangesDialog.ContentText, null, __13("To avoid losing your updates, save your changes before leaving.", "elementor"))), /* @__PURE__ */ React17.createElement(
2137
+ __14("Save changes", "elementor")
2138
+ ))))), /* @__PURE__ */ React18.createElement(ClassManagerIntroduction, null), isSaveChangesDialogOpen && /* @__PURE__ */ React18.createElement(SaveChangesDialog, null, /* @__PURE__ */ React18.createElement(DialogHeader2, { onClose: closeSaveChangesDialog, logo: false }, /* @__PURE__ */ React18.createElement(SaveChangesDialog.Title, null, __14("You have unsaved changes", "elementor"))), /* @__PURE__ */ React18.createElement(SaveChangesDialog.Content, null, /* @__PURE__ */ React18.createElement(SaveChangesDialog.ContentText, null, __14("You have unsaved changes in the Class Manager.", "elementor")), /* @__PURE__ */ React18.createElement(SaveChangesDialog.ContentText, null, __14("To avoid losing your updates, save your changes before leaving.", "elementor"))), /* @__PURE__ */ React18.createElement(
1819
2139
  SaveChangesDialog.Actions,
1820
2140
  {
1821
2141
  actions: {
1822
2142
  discard: {
1823
- label: __13("Discard", "elementor"),
2143
+ label: __14("Discard", "elementor"),
1824
2144
  action: () => {
1825
2145
  resetAndClosePanel();
1826
2146
  }
1827
2147
  },
1828
2148
  confirm: {
1829
- label: __13("Save & Continue", "elementor"),
2149
+ label: __14("Save & Continue", "elementor"),
1830
2150
  action: async () => {
1831
2151
  await publish();
1832
2152
  closeSaveChangesDialog();
@@ -1837,11 +2157,11 @@ function ClassManagerPanel() {
1837
2157
  }
1838
2158
  )));
1839
2159
  }
1840
- var CloseButton = ({ onClose, ...props }) => /* @__PURE__ */ React17.createElement(IconButton4, { size: "small", color: "secondary", onClick: onClose, "aria-label": "Close", ...props }, /* @__PURE__ */ React17.createElement(XIcon, { fontSize: "small" }));
1841
- var ErrorBoundaryFallback = () => /* @__PURE__ */ React17.createElement(Box9, { role: "alert", sx: { minHeight: "100%", p: 2 } }, /* @__PURE__ */ React17.createElement(Alert, { severity: "error", sx: { mb: 2, maxWidth: 400, textAlign: "center" } }, /* @__PURE__ */ React17.createElement("strong", null, __13("Something went wrong", "elementor"))));
2160
+ var CloseButton = ({ onClose, ...props }) => /* @__PURE__ */ React18.createElement(IconButton4, { size: "small", color: "secondary", onClick: onClose, "aria-label": "Close", ...props }, /* @__PURE__ */ React18.createElement(XIcon, { fontSize: "small" }));
2161
+ var ErrorBoundaryFallback = () => /* @__PURE__ */ React18.createElement(Box10, { role: "alert", sx: { minHeight: "100%", p: 2 } }, /* @__PURE__ */ React18.createElement(Alert2, { severity: "error", sx: { mb: 2, maxWidth: 400, textAlign: "center" } }, /* @__PURE__ */ React18.createElement("strong", null, __14("Something went wrong", "elementor"))));
1842
2162
  var usePreventUnload = () => {
1843
2163
  const isDirty2 = useDirtyState();
1844
- useEffect2(() => {
2164
+ useEffect3(() => {
1845
2165
  const handleBeforeUnload = (event) => {
1846
2166
  if (isDirty2) {
1847
2167
  event.preventDefault();
@@ -1867,7 +2187,7 @@ var usePublish = () => {
1867
2187
  var TotalCssClassCounter = () => {
1868
2188
  const filters = useFilters();
1869
2189
  const cssClasses = useClassesOrder();
1870
- return /* @__PURE__ */ React17.createElement(
2190
+ return /* @__PURE__ */ React18.createElement(
1871
2191
  Chip4,
1872
2192
  {
1873
2193
  size: "small",
@@ -1877,11 +2197,17 @@ var TotalCssClassCounter = () => {
1877
2197
  };
1878
2198
 
1879
2199
  // src/components/class-manager/class-manager-button.tsx
2200
+ var trackGlobalClassesButton = () => {
2201
+ trackGlobalClasses({
2202
+ event: "classManagerOpened",
2203
+ source: "style-panel"
2204
+ });
2205
+ };
1880
2206
  var ClassManagerButton = () => {
1881
2207
  const document = useActiveDocument2();
1882
2208
  const { open: openPanel } = usePanelActions();
1883
2209
  const { save: saveDocument } = useActiveDocumentActions();
1884
- const { open: openSaveChangesDialog, close: closeSaveChangesDialog, isOpen: isSaveChangesDialogOpen } = useDialog();
2210
+ const { open: openSaveChangesDialog, close: closeSaveChangesDialog, isOpen: isSaveChangesDialogOpen } = useDialog2();
1885
2211
  const { prefetchClassesUsage } = usePrefetchCssClassUsage();
1886
2212
  const { userCan } = useUserStylesCapability();
1887
2213
  const isUserAllowedToUpdateClass = userCan(globalClassesStylesProvider.getKey()).update;
@@ -1894,25 +2220,31 @@ var ClassManagerButton = () => {
1894
2220
  return;
1895
2221
  }
1896
2222
  openPanel();
2223
+ trackGlobalClassesButton();
2224
+ trackGlobalClasses({
2225
+ event: "classManagerOpened",
2226
+ source: "style-panel"
2227
+ });
1897
2228
  prefetchClassesUsage();
1898
2229
  };
1899
- return /* @__PURE__ */ React18.createElement(React18.Fragment, null, /* @__PURE__ */ React18.createElement(Tooltip6, { title: __14("Class Manager", "elementor"), placement: "top" }, /* @__PURE__ */ React18.createElement(IconButton5, { size: "tiny", onClick: handleOpenPanel, sx: { marginInlineEnd: -0.75 } }, /* @__PURE__ */ React18.createElement(FlippedColorSwatchIcon, { fontSize: "tiny" }))), isSaveChangesDialogOpen && /* @__PURE__ */ React18.createElement(SaveChangesDialog, null, /* @__PURE__ */ React18.createElement(SaveChangesDialog.Title, null, __14("You have unsaved changes", "elementor")), /* @__PURE__ */ React18.createElement(SaveChangesDialog.Content, null, /* @__PURE__ */ React18.createElement(SaveChangesDialog.ContentText, { sx: { mb: 2 } }, __14(
2230
+ return /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement(Tooltip6, { title: __15("Class Manager", "elementor"), placement: "top" }, /* @__PURE__ */ React19.createElement(IconButton5, { size: "tiny", onClick: handleOpenPanel, sx: { marginInlineEnd: -0.75 } }, /* @__PURE__ */ React19.createElement(FlippedColorSwatchIcon, { fontSize: "tiny" }))), isSaveChangesDialogOpen && /* @__PURE__ */ React19.createElement(SaveChangesDialog2, null, /* @__PURE__ */ React19.createElement(SaveChangesDialog2.Title, null, __15("You have unsaved changes", "elementor")), /* @__PURE__ */ React19.createElement(SaveChangesDialog2.Content, null, /* @__PURE__ */ React19.createElement(SaveChangesDialog2.ContentText, { sx: { mb: 2 } }, __15(
1900
2231
  "To open the Class Manager, save your page first. You can't continue without saving.",
1901
2232
  "elementor"
1902
- ))), /* @__PURE__ */ React18.createElement(
1903
- SaveChangesDialog.Actions,
2233
+ ))), /* @__PURE__ */ React19.createElement(
2234
+ SaveChangesDialog2.Actions,
1904
2235
  {
1905
2236
  actions: {
1906
2237
  cancel: {
1907
- label: __14("Stay here", "elementor"),
2238
+ label: __15("Stay here", "elementor"),
1908
2239
  action: closeSaveChangesDialog
1909
2240
  },
1910
2241
  confirm: {
1911
- label: __14("Save & Continue", "elementor"),
2242
+ label: __15("Save & Continue", "elementor"),
1912
2243
  action: async () => {
1913
2244
  await saveDocument();
1914
2245
  closeSaveChangesDialog();
1915
2246
  openPanel();
2247
+ trackGlobalClassesButton();
1916
2248
  prefetchClassesUsage();
1917
2249
  }
1918
2250
  }
@@ -1922,11 +2254,11 @@ var ClassManagerButton = () => {
1922
2254
  };
1923
2255
 
1924
2256
  // src/components/convert-local-class-to-global-class.tsx
1925
- import * as React19 from "react";
2257
+ import * as React20 from "react";
1926
2258
  import { validateStyleLabel as validateStyleLabel2 } from "@elementor/editor-styles-repository";
1927
2259
  import { MenuListItem as MenuListItem2 } from "@elementor/editor-ui";
1928
- import { Divider as Divider4 } from "@elementor/ui";
1929
- import { __ as __15 } from "@wordpress/i18n";
2260
+ import { Divider as Divider5 } from "@elementor/ui";
2261
+ import { __ as __16 } from "@wordpress/i18n";
1930
2262
  var ConvertLocalClassToGlobalClass = (props) => {
1931
2263
  const localStyleData = props.styleDef;
1932
2264
  const handleConversion = () => {
@@ -1937,9 +2269,15 @@ var ConvertLocalClassToGlobalClass = (props) => {
1937
2269
  const newId = globalClassesStylesProvider.actions.create?.(newClassName, localStyleData.variants);
1938
2270
  if (newId) {
1939
2271
  props.successCallback(newId);
2272
+ trackGlobalClasses({
2273
+ classId: newId,
2274
+ event: "classCreated",
2275
+ source: "converted",
2276
+ classTitle: newClassName
2277
+ });
1940
2278
  }
1941
2279
  };
1942
- return /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement(
2280
+ return /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement(
1943
2281
  MenuListItem2,
1944
2282
  {
1945
2283
  disabled: !props.canConvert,
@@ -1953,8 +2291,8 @@ var ConvertLocalClassToGlobalClass = (props) => {
1953
2291
  }
1954
2292
  }
1955
2293
  },
1956
- __15("Convert to global class", "elementor")
1957
- ), /* @__PURE__ */ React19.createElement(Divider4, null));
2294
+ __16("Convert to global class", "elementor")
2295
+ ), /* @__PURE__ */ React20.createElement(Divider5, null));
1958
2296
  };
1959
2297
  function createClassName(prefix) {
1960
2298
  let i = 1;
@@ -1966,11 +2304,11 @@ function createClassName(prefix) {
1966
2304
  }
1967
2305
 
1968
2306
  // src/components/populate-store.tsx
1969
- import { useEffect as useEffect3 } from "react";
2307
+ import { useEffect as useEffect4 } from "react";
1970
2308
  import { __useDispatch as useDispatch2 } from "@elementor/store";
1971
2309
  function PopulateStore() {
1972
2310
  const dispatch5 = useDispatch2();
1973
- useEffect3(() => {
2311
+ useEffect4(() => {
1974
2312
  Promise.all([apiClient.all("preview"), apiClient.all("frontend")]).then(
1975
2313
  ([previewRes, frontendRes]) => {
1976
2314
  const { data: previewData } = previewRes;
@@ -1993,14 +2331,223 @@ function PopulateStore() {
1993
2331
  return null;
1994
2332
  }
1995
2333
 
2334
+ // src/mcp-integration/index.ts
2335
+ import { getMCPByDomain as getMCPByDomain2 } from "@elementor/editor-mcp";
2336
+
2337
+ // src/mcp-integration/classes-resource.ts
2338
+ import { getMCPByDomain } from "@elementor/editor-mcp";
2339
+ var GLOBAL_CLASSES_URI = "elementor://classes";
2340
+ var initClassesResource = () => {
2341
+ const { mcpServer } = getMCPByDomain("classes");
2342
+ mcpServer.resource(
2343
+ "global-classes",
2344
+ GLOBAL_CLASSES_URI,
2345
+ {
2346
+ description: "Global classes list."
2347
+ },
2348
+ async () => {
2349
+ return {
2350
+ contents: [{ uri: GLOBAL_CLASSES_URI, text: localStorage["elementor-global-classes"] ?? {} }]
2351
+ };
2352
+ }
2353
+ );
2354
+ };
2355
+
2356
+ // src/mcp-integration/mcp-apply-unapply-global-classes.ts
2357
+ import { doApplyClasses, doGetAppliedClasses, doUnapplyClass } from "@elementor/editor-editing-panel";
2358
+ import { stylesRepository } from "@elementor/editor-styles-repository";
2359
+ import { z } from "@elementor/schema";
2360
+ function initMcpApplyUnapplyGlobalClasses(server) {
2361
+ server.addTool({
2362
+ name: "list-all-global-classes",
2363
+ description: `List all classes applied to a specific element
2364
+
2365
+ ## When to use this tool:
2366
+ - When a user requests to see which classes or global classes exists.
2367
+ - When you need the list of global classes to allow the user to select from.
2368
+ - At least once before applying or unapplying a class, to ensure the class ID is correct.
2369
+
2370
+ `,
2371
+ outputSchema: {
2372
+ appliedClasses: z.array(
2373
+ z.object({
2374
+ id: z.string().describe("The ID of the class"),
2375
+ label: z.string().describe("The label of the class"),
2376
+ variants: z.array(
2377
+ z.object({
2378
+ meta: z.object({
2379
+ breakpoint: z.string().optional(),
2380
+ state: z.string().optional()
2381
+ }),
2382
+ props: z.record(z.any())
2383
+ })
2384
+ )
2385
+ })
2386
+ )
2387
+ },
2388
+ handler: async () => {
2389
+ const globalClassesProvider = stylesRepository.getProviderByKey("global-classes");
2390
+ if (!globalClassesProvider) {
2391
+ throw new Error("Global classes provider not found");
2392
+ }
2393
+ const result = [];
2394
+ globalClassesProvider.actions.all().forEach((style) => {
2395
+ const { id: id2, label, variants } = style;
2396
+ result.push({
2397
+ id: id2,
2398
+ label,
2399
+ variants: variants.map((variant) => ({
2400
+ meta: {
2401
+ breakpoint: variant.meta.breakpoint,
2402
+ state: variant.meta.state
2403
+ },
2404
+ props: variant.props
2405
+ }))
2406
+ });
2407
+ });
2408
+ return { appliedClasses: result };
2409
+ }
2410
+ });
2411
+ server.addTool({
2412
+ schema: {
2413
+ classId: z.string().describe("The ID of the class to apply"),
2414
+ elementId: z.string().describe("The ID of the element to which the class will be applied")
2415
+ },
2416
+ name: "apply-global-class",
2417
+ description: `Apply a global class to the current element
2418
+
2419
+ ## When to use this tool:
2420
+ - When a user requests to apply a global class or a class to an element in the Elementor editor.
2421
+ - When you need to add a specific class to an element's applied classes.
2422
+
2423
+ ## Prerequisites:
2424
+ - Ensure you have the most up-to-date list of classes applied to the element to avoid duplicates. You can use the "list-applied-classes" tool to fetch the current classes.
2425
+ - Make sure you have the correct class ID that you want to apply.`,
2426
+ handler: async (params) => {
2427
+ const { classId, elementId } = params;
2428
+ const appliedClasses = doGetAppliedClasses(elementId);
2429
+ doApplyClasses(elementId, [...appliedClasses, classId]);
2430
+ return `Class ${classId} applied to element ${elementId} successfully.`;
2431
+ }
2432
+ });
2433
+ server.addTool({
2434
+ name: "unapply-global-class",
2435
+ schema: {
2436
+ classId: z.string().describe("The ID of the class to unapply"),
2437
+ elementId: z.string().describe("The ID of the element from which the class will be unapplied")
2438
+ },
2439
+ description: `Unapply a (global) class from the current element
2440
+
2441
+ ## When to use this tool:
2442
+ - When a user requests to unapply a global class or a class from an element in the Elementor editor.
2443
+ - When you need to remove a specific class from an element's applied classes.
2444
+
2445
+ ## Prerequisites:
2446
+ - Ensure you have the most up-to-date list of classes applied to the element to avoid errors. You can use the "list-global-classes" tool to fetch the all classes applied to all elements.
2447
+ - Make sure you have the correct class ID that you want to unapply.
2448
+
2449
+ <note>
2450
+ If the user want to unapply a class by it's name and not ID, please use the "list-global-classes" tool to get the class ID from the name first.
2451
+ </note>
2452
+ `,
2453
+ handler: async (params) => {
2454
+ const { classId, elementId } = params;
2455
+ const ok = doUnapplyClass(elementId, classId);
2456
+ if (!ok) {
2457
+ throw new Error(`Class ${classId} is not applied to element ${elementId}, cannot unapply it.`);
2458
+ }
2459
+ return `Class ${classId} unapplied from element ${elementId} successfully.`;
2460
+ }
2461
+ });
2462
+ }
2463
+
2464
+ // src/mcp-integration/mcp-get-global-class-usages.ts
2465
+ import { z as z2 } from "@elementor/schema";
2466
+ function initMcpApplyGetGlobalClassUsages(reg) {
2467
+ const { addTool } = reg;
2468
+ const globalClassesUsageSchema = {
2469
+ usages: z2.array(
2470
+ z2.object({
2471
+ classId: z2.string().describe(
2472
+ 'The ID of the class, not visible to the user. To retreive the name of the class, use the "list-global-classes" tool'
2473
+ ),
2474
+ usages: z2.array(
2475
+ z2.object({
2476
+ pageId: z2.string().describe("The ID of the page where the class is used"),
2477
+ title: z2.string().describe("The title of the page where the class is used"),
2478
+ total: z2.number().describe("The number of times the class is used on this page"),
2479
+ elements: z2.array(z2.string()).describe("List of element IDs using this class on the page")
2480
+ })
2481
+ )
2482
+ })
2483
+ )
2484
+ };
2485
+ addTool({
2486
+ name: "get-global-class-usages",
2487
+ description: `Retreive the usage details of global classes within the Elementor editor, accross all pages.
2488
+
2489
+ ## Prequisites:
2490
+ - Use "list-global-classes" tool to be able to match class IDs to class names/labels.
2491
+
2492
+ ## When to use this tool:
2493
+ - When a user requests to see where a specific global class is being used accross the site.
2494
+ - When you need to manage or clean up unused global classes.
2495
+ - Before deleting a global class, to ensure it is not in use in any other pages.
2496
+ `,
2497
+ outputSchema: globalClassesUsageSchema,
2498
+ handler: async () => {
2499
+ const data = await fetchCssClassUsage();
2500
+ const result = {
2501
+ usages: []
2502
+ };
2503
+ Object.entries(data).forEach(
2504
+ ([classId, usageDetails]) => {
2505
+ const newEntry = {
2506
+ classId,
2507
+ usages: []
2508
+ };
2509
+ if (typeof usageDetails !== "number") {
2510
+ const { content } = usageDetails;
2511
+ content.forEach((detail) => {
2512
+ newEntry.usages.push({
2513
+ pageId: String(detail.pageId),
2514
+ title: detail.title,
2515
+ total: detail.total,
2516
+ elements: detail.elements
2517
+ });
2518
+ });
2519
+ result.usages.push(newEntry);
2520
+ }
2521
+ }
2522
+ );
2523
+ return result;
2524
+ }
2525
+ });
2526
+ }
2527
+
2528
+ // src/mcp-integration/index.ts
2529
+ var initMcpIntegration = () => {
2530
+ const reg = getMCPByDomain2("classes");
2531
+ reg.setMCPDescription(
2532
+ "Tools for managing and applying Global CSS classes to elements within the Elementor editor."
2533
+ );
2534
+ initMcpApplyUnapplyGlobalClasses(reg);
2535
+ initMcpApplyGetGlobalClassUsages(reg);
2536
+ initClassesResource();
2537
+ };
2538
+
2539
+ // src/sync-with-document.tsx
2540
+ import { useEffect as useEffect5 } from "react";
2541
+ import { __privateListenTo as listenTo, v1ReadyEvent } from "@elementor/editor-v1-adapters";
2542
+
1996
2543
  // src/sync-with-document-save.ts
1997
2544
  import { getCurrentUser } from "@elementor/editor-current-user";
1998
2545
  import { setDocumentModifiedStatus as setDocumentModifiedStatus2 } from "@elementor/editor-documents";
1999
2546
  import { registerDataHook } from "@elementor/editor-v1-adapters";
2000
- import { __getState as getState3, __subscribeWithSelector as subscribeWithSelector2 } from "@elementor/store";
2001
- function syncWithDocumentSave() {
2547
+ import { __getState as getState4, __subscribeWithSelector as subscribeWithSelector2 } from "@elementor/store";
2548
+ function syncWithDocumentSave(panelActions) {
2002
2549
  const unsubscribe = syncDirtyState();
2003
- bindSaveAction();
2550
+ bindSaveAction(panelActions);
2004
2551
  return unsubscribe;
2005
2552
  }
2006
2553
  function syncDirtyState() {
@@ -2011,31 +2558,52 @@ function syncDirtyState() {
2011
2558
  setDocumentModifiedStatus2(true);
2012
2559
  });
2013
2560
  }
2014
- function bindSaveAction() {
2015
- registerDataHook("after", "document/save/save", (args) => {
2561
+ function bindSaveAction(panelActions) {
2562
+ registerDataHook("dependency", "document/save/save", (args) => {
2016
2563
  const user = getCurrentUser();
2017
2564
  const canEdit = user?.capabilities.includes(UPDATE_CLASS_CAPABILITY_KEY);
2018
2565
  if (!canEdit) {
2019
- return;
2566
+ return true;
2020
2567
  }
2021
- return saveGlobalClasses({
2022
- context: args.status === "publish" ? "frontend" : "preview"
2568
+ saveGlobalClasses({
2569
+ context: args.status === "publish" ? "frontend" : "preview",
2570
+ onApprove: panelActions?.open
2023
2571
  });
2572
+ return true;
2024
2573
  });
2025
2574
  }
2026
2575
  function isDirty() {
2027
- return selectIsDirty(getState3());
2576
+ return selectIsDirty(getState4());
2577
+ }
2578
+
2579
+ // src/sync-with-document.tsx
2580
+ function SyncWithDocumentSave() {
2581
+ const panelActions = usePanelActions();
2582
+ useEffect5(() => {
2583
+ listenTo(v1ReadyEvent(), () => {
2584
+ syncWithDocumentSave(panelActions);
2585
+ });
2586
+ }, []);
2587
+ return null;
2028
2588
  }
2029
2589
 
2030
2590
  // src/init.ts
2031
2591
  function init() {
2032
2592
  registerSlice(slice);
2033
2593
  registerPanel(panel);
2034
- stylesRepository.register(globalClassesStylesProvider);
2594
+ stylesRepository2.register(globalClassesStylesProvider);
2035
2595
  injectIntoLogic({
2036
2596
  id: "global-classes-populate-store",
2037
2597
  component: PopulateStore
2038
2598
  });
2599
+ injectIntoLogic({
2600
+ id: "global-classes-sync-with-document",
2601
+ component: SyncWithDocumentSave
2602
+ });
2603
+ injectIntoLogic({
2604
+ id: "global-classes-prefetch-css-class-usage",
2605
+ component: PrefetchCssClassUsage
2606
+ });
2039
2607
  injectIntoCssClassConvert({
2040
2608
  id: "global-classes-convert-from-local-class",
2041
2609
  component: ConvertLocalClassToGlobalClass
@@ -2048,9 +2616,7 @@ function init() {
2048
2616
  name: "global",
2049
2617
  getThemeColor: (theme) => theme.palette.global.dark
2050
2618
  });
2051
- listenTo(v1ReadyEvent(), () => {
2052
- syncWithDocumentSave();
2053
- });
2619
+ initMcpIntegration();
2054
2620
  }
2055
2621
  export {
2056
2622
  init