@elementor/editor-global-classes 4.1.0-manual → 4.2.0-839

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,28 +1,45 @@
1
- // src/global-classes-styles-provider.ts
2
- import { generateId } from "@elementor/editor-styles";
3
- import { createStylesProvider } from "@elementor/editor-styles-repository";
1
+ // src/components/class-manager/class-manager-panel.tsx
2
+ import * as React19 from "react";
3
+ import { useCallback, useEffect as useEffect4, useMemo as useMemo4, useState as useState7 } from "react";
4
+ import { useSuppressedMessage as useSuppressedMessage2 } from "@elementor/editor-current-user";
5
+ import { reloadCurrentDocument, setDocumentModifiedStatus } from "@elementor/editor-documents";
4
6
  import {
5
- __dispatch as dispatch,
6
- __getState as getState2,
7
- __subscribeWithSelector as subscribeWithSelector
8
- } from "@elementor/store";
9
- import { __ } from "@wordpress/i18n";
7
+ __createPanel as createPanel,
8
+ Panel,
9
+ PanelBody,
10
+ PanelFooter,
11
+ PanelHeader,
12
+ PanelHeaderTitle
13
+ } from "@elementor/editor-panels";
14
+ import { ConfirmationDialog as ConfirmationDialog2, SaveChangesDialog, ThemeProvider, useDialog } from "@elementor/editor-ui";
15
+ import { changeEditMode } from "@elementor/editor-v1-adapters";
16
+ import { XIcon } from "@elementor/icons";
17
+ import { useMutation } from "@elementor/query";
18
+ import { __dispatch as dispatch3 } from "@elementor/store";
19
+ import {
20
+ Alert as Alert2,
21
+ Box as Box11,
22
+ Button as Button3,
23
+ Chip as Chip4,
24
+ DialogHeader as DialogHeader2,
25
+ Divider as Divider4,
26
+ ErrorBoundary,
27
+ IconButton as IconButton4,
28
+ Stack as Stack9
29
+ } from "@elementor/ui";
30
+ import { __ as __14 } from "@wordpress/i18n";
10
31
 
11
- // src/capabilities.ts
12
- import { isExperimentActive } from "@elementor/editor-v1-adapters";
13
- var EXPERIMENT_KEY = "global_classes_should_enforce_capabilities";
14
- var UPDATE_CLASS_CAPABILITY_KEY = "elementor_global_classes_update_class";
15
- var getCapabilities = () => {
16
- const shouldEnforceCapabilities = isExperimentActive(EXPERIMENT_KEY);
17
- if (shouldEnforceCapabilities) {
18
- return {
19
- update: UPDATE_CLASS_CAPABILITY_KEY,
20
- create: UPDATE_CLASS_CAPABILITY_KEY,
21
- delete: UPDATE_CLASS_CAPABILITY_KEY,
22
- updateProps: UPDATE_CLASS_CAPABILITY_KEY
23
- };
24
- }
25
- };
32
+ // src/hooks/use-classes-order.ts
33
+ import { __useSelector as useSelector } from "@elementor/store";
34
+
35
+ // src/store.ts
36
+ import {
37
+ getVariantByMeta
38
+ } from "@elementor/editor-styles";
39
+ import {
40
+ __createSelector as createSelector,
41
+ __createSlice as createSlice
42
+ } from "@elementor/store";
26
43
 
27
44
  // src/errors.ts
28
45
  import { createError } from "@elementor/utils";
@@ -39,15 +56,6 @@ var GlobalClassTrackingError = createError({
39
56
  message: "Error tracking global classes event."
40
57
  });
41
58
 
42
- // src/store.ts
43
- import {
44
- getVariantByMeta
45
- } from "@elementor/editor-styles";
46
- import {
47
- __createSelector as createSelector,
48
- __createSlice as createSlice
49
- } from "@elementor/store";
50
-
51
59
  // src/utils/snapshot-history.ts
52
60
  function createLink({ value, next, prev }) {
53
61
  return {
@@ -112,6 +120,7 @@ var SnapshotHistory = class _SnapshotHistory {
112
120
  var localHistory = SnapshotHistory.get("global-classes");
113
121
  var initialState = {
114
122
  data: { items: {}, order: [] },
123
+ classLabels: {},
115
124
  initialData: {
116
125
  frontend: { items: {}, order: [] },
117
126
  preview: { items: {}, order: [] }
@@ -124,17 +133,19 @@ var slice = createSlice({
124
133
  initialState,
125
134
  reducers: {
126
135
  load(state, {
127
- payload: { frontend, preview }
136
+ payload: { frontend, preview, classLabels }
128
137
  }) {
129
138
  state.initialData.frontend = frontend;
130
139
  state.initialData.preview = preview;
131
140
  state.data = preview;
141
+ state.classLabels = classLabels;
132
142
  state.isDirty = false;
133
143
  },
134
144
  add(state, { payload }) {
135
145
  localHistory.next(state.data);
136
146
  state.data.items[payload.id] = payload;
137
147
  state.data.order.unshift(payload.id);
148
+ state.classLabels[payload.id] = payload.label;
138
149
  state.isDirty = true;
139
150
  },
140
151
  delete(state, { payload }) {
@@ -143,6 +154,7 @@ var slice = createSlice({
143
154
  Object.entries(state.data.items).filter(([id2]) => id2 !== payload)
144
155
  );
145
156
  state.data.order = state.data.order.filter((id2) => id2 !== payload);
157
+ delete state.classLabels[payload];
146
158
  state.isDirty = true;
147
159
  },
148
160
  setOrder(state, { payload }) {
@@ -164,6 +176,7 @@ var slice = createSlice({
164
176
  localHistory.next(state.data);
165
177
  Object.entries(payload).forEach(([id2, { modified }]) => {
166
178
  state.data.items[id2].label = modified;
179
+ state.classLabels[id2] = modified;
167
180
  });
168
181
  state.isDirty = false;
169
182
  },
@@ -179,9 +192,14 @@ var slice = createSlice({
179
192
  let customCss = ("custom_css" in payload ? payload.custom_css : variant?.custom_css) ?? null;
180
193
  customCss = customCss?.raw ? customCss : null;
181
194
  if (variant) {
182
- const variantProps = JSON.parse(JSON.stringify(variant.props));
183
195
  const payloadProps = JSON.parse(JSON.stringify(payload.props));
184
- variant.props = mergeProps(variantProps, payloadProps);
196
+ const mode = payload.mode ?? "merge";
197
+ if (mode === "replace") {
198
+ variant.props = payloadProps;
199
+ } else {
200
+ const variantProps = JSON.parse(JSON.stringify(variant.props));
201
+ variant.props = mergeProps(variantProps, payloadProps);
202
+ }
185
203
  variant.custom_css = customCss;
186
204
  style.variants = getNonEmptyVariants(style);
187
205
  } else {
@@ -223,6 +241,28 @@ var slice = createSlice({
223
241
  state.data = data;
224
242
  state.isDirty = true;
225
243
  }
244
+ },
245
+ mergeExistingClasses(state, {
246
+ payload: { preview, frontend }
247
+ }) {
248
+ Object.entries(preview).forEach(([id2, previewClassData]) => {
249
+ const frontendClassData = frontend[id2];
250
+ if (previewClassData === null || previewClassData === void 0) {
251
+ return;
252
+ }
253
+ if (!(id2 in state.data.items)) {
254
+ state.data.items[id2] = previewClassData;
255
+ }
256
+ if (!(id2 in state.initialData.frontend.items)) {
257
+ state.initialData.frontend.items[id2] = frontendClassData;
258
+ }
259
+ if (!(id2 in state.initialData.preview.items)) {
260
+ state.initialData.preview.items[id2] = previewClassData;
261
+ }
262
+ if (!(id2 in state.classLabels)) {
263
+ state.classLabels[id2] = previewClassData.label;
264
+ }
265
+ });
226
266
  }
227
267
  }
228
268
  });
@@ -242,404 +282,39 @@ var getNonEmptyVariants = (style) => {
242
282
  ({ props, custom_css: customCss }) => Object.keys(props).length || customCss?.raw
243
283
  );
244
284
  };
285
+ var placeholderDefinition = (id2, label) => ({
286
+ id: id2,
287
+ type: "class",
288
+ label,
289
+ variants: []
290
+ });
245
291
  var selectData = (state) => state[SLICE_NAME].data;
292
+ var selectClassLabels = (state) => state[SLICE_NAME].classLabels;
246
293
  var selectFrontendInitialData = (state) => state[SLICE_NAME].initialData.frontend;
247
294
  var selectPreviewInitialData = (state) => state[SLICE_NAME].initialData.preview;
248
295
  var selectOrder = createSelector(selectData, ({ order }) => order);
249
296
  var selectGlobalClasses = createSelector(selectData, ({ items }) => items);
250
297
  var selectIsDirty = (state) => state[SLICE_NAME].isDirty;
251
298
  var selectOrderedClasses = createSelector(
252
- selectGlobalClasses,
253
- selectOrder,
254
- (items, order) => order.map((id2) => items[id2])
299
+ selectData,
300
+ selectClassLabels,
301
+ ({ items, order }, classLabels) => order.map((id2) => {
302
+ const loaded = items[id2];
303
+ if (loaded) {
304
+ return loaded;
305
+ }
306
+ const label = classLabels[id2];
307
+ return label !== void 0 ? placeholderDefinition(id2, label) : null;
308
+ }).filter((s) => s !== null)
255
309
  );
256
310
  var selectClass = (state, id2) => state[SLICE_NAME].data.items[id2] ?? null;
257
311
  var selectEmptyCssClass = createSelector(
258
312
  selectData,
259
313
  ({ items }) => Object.values(items).filter((cssClass) => cssClass.variants.length === 0)
260
314
  );
261
-
262
- // src/utils/tracking.ts
263
- import { getMixpanel } from "@elementor/events";
264
- import { __getState as getState } from "@elementor/store";
265
-
266
- // src/api.ts
267
- import { httpService } from "@elementor/http-client";
268
- var RESOURCE_URL = "/global-classes";
269
- var BASE_URL = "elementor/v1";
270
- var RESOURCE_USAGE_URL = `${RESOURCE_URL}/usage`;
271
- var apiClient = {
272
- usage: () => httpService().get(`${BASE_URL}${RESOURCE_USAGE_URL}`),
273
- all: (context2 = "preview") => httpService().get(`${BASE_URL}${RESOURCE_URL}`, {
274
- params: { context: context2 }
275
- }),
276
- publish: (payload) => httpService().put("elementor/v1" + RESOURCE_URL, payload, {
277
- params: {
278
- context: "frontend"
279
- }
280
- }),
281
- saveDraft: (payload) => httpService().put("elementor/v1" + RESOURCE_URL, payload, {
282
- params: {
283
- context: "preview"
284
- }
285
- })
286
- };
287
- var API_ERROR_CODES = {
288
- DUPLICATED_LABEL: "DUPLICATED_LABEL"
289
- };
290
-
291
- // src/components/css-class-usage/utils.ts
292
- var transformData = (data) => Object.entries(data).reduce((acc, [key, value]) => {
293
- acc[key] = {
294
- content: value || [],
295
- total: value.reduce((total, val) => total + (val?.total || 0), 0)
296
- };
297
- return acc;
298
- }, {});
299
-
300
- // service/css-class-usage-service.ts
301
- var fetchCssClassUsage = async () => {
302
- const response = await apiClient.usage();
303
- return transformData(response?.data?.data || {});
304
- };
305
-
306
- // src/utils/tracking.ts
307
- var trackGlobalClasses = async (payload) => {
308
- const { runAction } = payload;
309
- const data = await getSanitizedData(payload);
310
- if (data) {
311
- track(data);
312
- if (data.event === "classCreated" && "classId" in data) {
313
- fireClassApplied(data.classId);
314
- }
315
- }
316
- runAction?.();
317
- };
318
- var fireClassApplied = async (classId) => {
319
- const appliedInfo = await getAppliedInfo(classId);
320
- track({
321
- event: "classApplied",
322
- classId,
323
- ...appliedInfo,
324
- totalInstancesAfterApply: 1
325
- });
326
- };
327
- var getSanitizedData = async (payload) => {
328
- switch (payload.event) {
329
- case "classApplied":
330
- if ("classId" in payload && payload.classId) {
331
- const appliedInfo = await getAppliedInfo(payload.classId);
332
- return { ...payload, ...appliedInfo };
333
- }
334
- break;
335
- case "classRemoved":
336
- if ("classId" in payload && payload.classId) {
337
- const deleteInfo = getRemovedInfo(payload.classId);
338
- return { ...payload, ...deleteInfo };
339
- }
340
- break;
341
- case "classDeleted":
342
- if ("classId" in payload && payload.classId) {
343
- const deleteInfo = await trackDeleteClass(payload.classId);
344
- return { ...payload, ...deleteInfo };
345
- }
346
- break;
347
- case "classCreated":
348
- if ("source" in payload && payload.source !== "created") {
349
- if ("classId" in payload && payload.classId) {
350
- return { ...payload, classTitle: getCssClass(payload.classId).label };
351
- }
352
- }
353
- return payload;
354
- case "classStateClicked":
355
- if ("classId" in payload && payload.classId) {
356
- return { ...payload, classTitle: getCssClass(payload.classId).label };
357
- }
358
- break;
359
- case "classSyncToV3PopupShown":
360
- return {
361
- ...payload,
362
- interaction_type: "popup_shown",
363
- target_type: "popup",
364
- target_name: "sync_to_v3_popup",
365
- interaction_result: "popup_viewed",
366
- target_location: "widget_panel",
367
- location_l1: "class_manager"
368
- };
369
- case "classSyncToV3": {
370
- const classLabel = getCssClass(payload.classId).label;
371
- const isSync = payload.action === "sync";
372
- return {
373
- ...payload,
374
- interaction_type: "click",
375
- target_type: classLabel,
376
- target_name: isSync ? "sync_to_v3" : "unsync_to_v3",
377
- interaction_result: isSync ? "class_is_synced_to_V3" : "class_is_unsynced_from_V3",
378
- target_location: "widget_panel",
379
- location_l1: "class_manager",
380
- interaction_description: isSync ? `user_synced_${classLabel}_to_v3` : `user_unsync_${classLabel}_from_v3`
381
- };
382
- }
383
- case "classSyncToV3PopupClick": {
384
- const isSyncAction = payload.action === "sync";
385
- return {
386
- ...payload,
387
- interaction_type: "click",
388
- target_type: "button",
389
- target_name: isSyncAction ? "sync_to_v3" : "cancel",
390
- interaction_result: isSyncAction ? "class_is_synced" : "cancel",
391
- target_location: "sync_to_v3_popup"
392
- };
393
- }
394
- default:
395
- return payload;
396
- }
397
- };
398
- var track = (data) => {
399
- const { dispatchEvent, config } = getMixpanel();
400
- if (!config?.names?.global_classes?.[data.event]) {
401
- console.error("Global class tracking event not found", { event: data.event });
402
- return;
403
- }
404
- const name = config.names.global_classes[data.event];
405
- const { event, ...eventData } = data;
406
- try {
407
- dispatchEvent?.(name, {
408
- event,
409
- ...eventData
410
- });
411
- } catch (error) {
412
- throw new GlobalClassTrackingError({ cause: error });
413
- }
414
- };
415
- var extractCssClassData = (classId) => {
416
- const cssClass = getCssClass(classId);
417
- const classTitle = cssClass.label;
418
- return { classTitle };
419
- };
420
- var getCssClass = (classId) => {
421
- const cssClass = selectClass(getState(), classId);
422
- if (!cssClass) {
423
- throw new Error(`CSS class with ID ${classId} not found`);
424
- }
425
- return cssClass;
426
- };
427
- var trackDeleteClass = async (classId) => {
428
- const totalInstances = await getTotalInstancesByCssClassID(classId);
429
- const classTitle = getCssClass(classId).label;
430
- return { totalInstances, classTitle };
431
- };
432
- var getTotalInstancesByCssClassID = async (classId) => {
433
- const cssClassUsage = await fetchCssClassUsage();
434
- return cssClassUsage[classId]?.total ?? 1;
435
- };
436
- var getAppliedInfo = async (classId) => {
437
- const { classTitle } = extractCssClassData(classId);
438
- const totalInstancesAfterApply = await getTotalInstancesByCssClassID(classId) + 1;
439
- return { classTitle, totalInstancesAfterApply };
440
- };
441
- var getRemovedInfo = (classId) => {
442
- const { classTitle } = extractCssClassData(classId);
443
- return {
444
- classTitle
445
- };
446
- };
447
-
448
- // src/global-classes-styles-provider.ts
449
- var MAX_CLASSES = 100;
450
- var GLOBAL_CLASSES_PROVIDER_KEY = "global-classes";
451
- var PREGENERATED_LINK_PATTERN = /^global-(preview|frontend)-[a-zA-Z_-]+-css$/;
452
- var globalClassesStylesProvider = createStylesProvider({
453
- key: GLOBAL_CLASSES_PROVIDER_KEY,
454
- priority: 30,
455
- limit: MAX_CLASSES,
456
- isPregeneratedLink: ({ id: id2 }) => PREGENERATED_LINK_PATTERN.test(id2),
457
- labels: {
458
- singular: __("class", "elementor"),
459
- plural: __("classes", "elementor")
460
- },
461
- subscribe: (cb) => subscribeWithStates(cb),
462
- capabilities: getCapabilities(),
463
- actions: {
464
- all: () => selectOrderedClasses(getState2()),
465
- get: (id2) => selectClass(getState2(), id2),
466
- resolveCssName: (id2) => {
467
- return selectClass(getState2(), id2)?.label ?? id2;
468
- },
469
- create: (label, variants = []) => {
470
- const classes = selectGlobalClasses(getState2());
471
- const existingLabels = Object.values(classes).map((style) => style.label);
472
- if (existingLabels.includes(label)) {
473
- throw new GlobalClassLabelAlreadyExistsError({ context: { label } });
474
- }
475
- const existingIds = Object.keys(classes);
476
- const id2 = generateId("g-", existingIds);
477
- dispatch(
478
- slice.actions.add({
479
- id: id2,
480
- type: "class",
481
- label,
482
- variants
483
- })
484
- );
485
- return id2;
486
- },
487
- update: (payload) => {
488
- dispatch(
489
- slice.actions.update({
490
- style: payload
491
- })
492
- );
493
- },
494
- delete: (id2) => {
495
- dispatch(slice.actions.delete(id2));
496
- },
497
- updateProps: (args) => {
498
- dispatch(
499
- slice.actions.updateProps({
500
- id: args.id,
501
- meta: args.meta,
502
- props: args.props
503
- })
504
- );
505
- },
506
- updateCustomCss: (args) => {
507
- dispatch(
508
- slice.actions.updateProps({
509
- id: args.id,
510
- meta: args.meta,
511
- custom_css: args.custom_css,
512
- props: {}
513
- })
514
- );
515
- },
516
- tracking: (data) => {
517
- trackGlobalClasses(data).catch((error) => {
518
- throw new GlobalClassTrackingError({ cause: error });
519
- });
520
- }
521
- }
522
- });
523
- var subscribeWithStates = (cb) => {
524
- let previousState = selectData(getState2());
525
- return subscribeWithSelector(
526
- (state) => state.globalClasses,
527
- (currentState) => {
528
- cb(previousState.items, currentState.data.items);
529
- previousState = currentState.data;
530
- }
531
- );
532
- };
533
-
534
- // src/mcp-integration/classes-resource.ts
535
- var GLOBAL_CLASSES_URI = "elementor://global-classes";
536
- var STORAGE_KEY = "elementor-global-classes";
537
- var updateLocalStorageCache = () => {
538
- const classes = globalClassesStylesProvider.actions.all();
539
- localStorage.setItem(STORAGE_KEY, JSON.stringify(classes));
540
- };
541
- var initClassesResource = (classesMcpEntry, canvasMcpEntry) => {
542
- [canvasMcpEntry, classesMcpEntry].forEach((entry) => {
543
- const { sendResourceUpdated, resource, waitForReady } = entry;
544
- resource(
545
- "global-classes",
546
- GLOBAL_CLASSES_URI,
547
- {
548
- description: "Global classes list."
549
- },
550
- async () => {
551
- return {
552
- contents: [{ uri: GLOBAL_CLASSES_URI, text: localStorage[STORAGE_KEY] ?? "[]" }]
553
- };
554
- }
555
- );
556
- waitForReady().then(() => {
557
- updateLocalStorageCache();
558
- globalClassesStylesProvider.subscribe(() => {
559
- updateLocalStorageCache();
560
- sendResourceUpdated({ uri: GLOBAL_CLASSES_URI });
561
- });
562
- });
563
- });
564
- };
565
-
566
- // src/init.ts
567
- import { injectIntoLogic } from "@elementor/editor";
568
- import {
569
- injectIntoClassSelectorActions,
570
- injectIntoCssClassConvert,
571
- registerStyleProviderToColors
572
- } from "@elementor/editor-editing-panel";
573
- import { getMCPByDomain } from "@elementor/editor-mcp";
574
- import { __registerPanel as registerPanel } from "@elementor/editor-panels";
575
- import { stylesRepository } from "@elementor/editor-styles-repository";
576
- import { __registerSlice as registerSlice } from "@elementor/store";
577
-
578
- // src/components/class-manager/class-manager-button.tsx
579
- import * as React20 from "react";
580
- import {
581
- __useActiveDocument as useActiveDocument2,
582
- __useActiveDocumentActions as useActiveDocumentActions
583
- } from "@elementor/editor-documents";
584
- import { useUserStylesCapability } from "@elementor/editor-styles-repository";
585
- import { SaveChangesDialog as SaveChangesDialog2, useDialog as useDialog2 } from "@elementor/editor-ui";
586
- import { IconButton as IconButton5, Tooltip as Tooltip6 } from "@elementor/ui";
587
- import { __ as __16 } from "@wordpress/i18n";
588
-
589
- // src/hooks/use-prefetch-css-class-usage.ts
590
- import { useQueryClient } from "@elementor/query";
591
-
592
- // src/components/css-class-usage/types.ts
593
- var QUERY_KEY = "css-classes-usage";
594
-
595
- // src/hooks/use-prefetch-css-class-usage.ts
596
- function usePrefetchCssClassUsage() {
597
- const queryClient = useQueryClient();
598
- const prefetchClassesUsage = () => queryClient.prefetchQuery({
599
- queryKey: [QUERY_KEY],
600
- queryFn: fetchCssClassUsage
601
- });
602
- return { prefetchClassesUsage };
603
- }
604
- var PrefetchCssClassUsage = () => {
605
- const { prefetchClassesUsage } = usePrefetchCssClassUsage();
606
- prefetchClassesUsage();
607
- return null;
608
- };
609
-
610
- // src/components/class-manager/class-manager-panel.tsx
611
- import * as React19 from "react";
612
- import { useCallback, useEffect as useEffect4, useState as useState7 } from "react";
613
- import { useSuppressedMessage as useSuppressedMessage2 } from "@elementor/editor-current-user";
614
- import { getCurrentDocument, getV1DocumentsManager, setDocumentModifiedStatus } from "@elementor/editor-documents";
615
- import {
616
- __createPanel as createPanel,
617
- Panel,
618
- PanelBody,
619
- PanelFooter,
620
- PanelHeader,
621
- PanelHeaderTitle
622
- } from "@elementor/editor-panels";
623
- import { ConfirmationDialog as ConfirmationDialog2, SaveChangesDialog, ThemeProvider, useDialog } from "@elementor/editor-ui";
624
- import { __privateRunCommand as runCommand, changeEditMode } from "@elementor/editor-v1-adapters";
625
- import { XIcon } from "@elementor/icons";
626
- import { useMutation } from "@elementor/query";
627
- import { __dispatch as dispatch4 } from "@elementor/store";
628
- import {
629
- Alert as Alert2,
630
- Box as Box11,
631
- Button as Button3,
632
- Chip as Chip4,
633
- DialogHeader as DialogHeader2,
634
- Divider as Divider4,
635
- ErrorBoundary,
636
- IconButton as IconButton4,
637
- Stack as Stack9
638
- } from "@elementor/ui";
639
- import { __ as __15 } from "@wordpress/i18n";
315
+ var selectIsClassFetched = (state, id2) => !!state[SLICE_NAME].initialData.preview.items[id2] || !!state[SLICE_NAME].initialData.frontend.items[id2] || false;
640
316
 
641
317
  // src/hooks/use-classes-order.ts
642
- import { __useSelector as useSelector } from "@elementor/store";
643
318
  var useClassesOrder = () => {
644
319
  return useSelector(selectOrder);
645
320
  };
@@ -711,12 +386,62 @@ var useSearchAndFilters = () => {
711
386
  return context2;
712
387
  };
713
388
 
714
- // src/hooks/use-filtered-css-class-usage.tsx
715
- import { useMemo } from "react";
716
- import { __useActiveDocument as useActiveDocument } from "@elementor/editor-documents";
389
+ // src/hooks/use-filtered-css-class-usage.tsx
390
+ import { useMemo } from "react";
391
+ import { __useActiveDocument as useActiveDocument } from "@elementor/editor-documents";
392
+
393
+ // src/hooks/use-css-class-usage.ts
394
+ import { useQuery } from "@elementor/query";
395
+
396
+ // src/api.ts
397
+ import { httpService } from "@elementor/http-client";
398
+ var RESOURCE_URL = "/global-classes";
399
+ var BASE_URL = "elementor/v1";
400
+ var RESOURCE_USAGE_URL = `${RESOURCE_URL}/usage`;
401
+ var RESOURCE_POST_URL = `${RESOURCE_URL}/post`;
402
+ var RESOURCE_STYLES_URL = `${RESOURCE_URL}/styles`;
403
+ function saveGlobalClasses(context2, payload) {
404
+ return httpService().put(`${BASE_URL}${RESOURCE_URL}`, payload, {
405
+ params: { context: context2 }
406
+ });
407
+ }
408
+ var apiClient = {
409
+ usage: () => httpService().get(`${BASE_URL}${RESOURCE_USAGE_URL}`),
410
+ all: (context2 = "preview") => httpService().get(`${BASE_URL}${RESOURCE_URL}`, {
411
+ params: { context: context2 }
412
+ }),
413
+ getStylesForPost: (postId, context2 = "preview") => httpService().get(`${BASE_URL}${RESOURCE_POST_URL}`, {
414
+ params: { context: context2, post_id: postId }
415
+ }),
416
+ getStylesByIds: (ids, context2 = "preview") => httpService().get(`${BASE_URL}${RESOURCE_STYLES_URL}`, {
417
+ params: { context: context2, ids: ids.join(",") }
418
+ }),
419
+ publish: (payload) => saveGlobalClasses("frontend", payload),
420
+ saveDraft: (payload) => saveGlobalClasses("preview", payload)
421
+ };
422
+ var API_ERROR_CODES = {
423
+ DUPLICATED_LABEL: "DUPLICATED_LABEL"
424
+ };
425
+
426
+ // src/components/css-class-usage/utils.ts
427
+ var transformData = (data) => Object.entries(data).reduce((acc, [key, value]) => {
428
+ acc[key] = {
429
+ content: value || [],
430
+ total: value.reduce((total, val) => total + (val?.total || 0), 0)
431
+ };
432
+ return acc;
433
+ }, {});
434
+
435
+ // service/css-class-usage-service.ts
436
+ var fetchCssClassUsage = async () => {
437
+ const response = await apiClient.usage();
438
+ return transformData(response?.data?.data || {});
439
+ };
440
+
441
+ // src/components/css-class-usage/types.ts
442
+ var QUERY_KEY = "css-classes-usage";
717
443
 
718
444
  // src/hooks/use-css-class-usage.ts
719
- import { useQuery } from "@elementor/query";
720
445
  var useCssClassUsage = () => {
721
446
  return useQuery({
722
447
  queryKey: [QUERY_KEY],
@@ -809,7 +534,7 @@ var useFilters = () => {
809
534
  // src/save-global-classes.tsx
810
535
  import * as React3 from "react";
811
536
  import { openDialog } from "@elementor/editor-ui";
812
- import { __dispatch as dispatch2, __getState as getState3 } from "@elementor/store";
537
+ import { __dispatch as dispatch, __getState as getState2 } from "@elementor/store";
813
538
  import { hash } from "@elementor/utils";
814
539
 
815
540
  // src/components/class-manager/duplicate-label-dialog.tsx
@@ -828,7 +553,7 @@ import {
828
553
  Stack,
829
554
  Typography
830
555
  } from "@elementor/ui";
831
- import { __ as __2 } from "@wordpress/i18n";
556
+ import { __ } from "@wordpress/i18n";
832
557
  var DUP_PREFIX = "DUP_";
833
558
  var DuplicateLabelDialog = ({
834
559
  modifiedLabels,
@@ -839,7 +564,7 @@ var DuplicateLabelDialog = ({
839
564
  onApprove?.();
840
565
  closeDialog();
841
566
  };
842
- 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(
567
+ 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" }, __("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" }, __(
843
568
  "Some new classes used the same names as existing ones. To prevent conflicts, we added the prefix",
844
569
  "elementor"
845
570
  ), /* @__PURE__ */ React2.createElement("strong", null, " ", DUP_PREFIX)), /* @__PURE__ */ React2.createElement(Box, null, /* @__PURE__ */ React2.createElement(
@@ -864,7 +589,7 @@ var DuplicateLabelDialog = ({
864
589
  minWidth: 0
865
590
  }
866
591
  },
867
- __2("Before", "elementor")
592
+ __("Before", "elementor")
868
593
  ),
869
594
  /* @__PURE__ */ React2.createElement(
870
595
  Typography,
@@ -879,7 +604,7 @@ var DuplicateLabelDialog = ({
879
604
  maxWidth: "200px"
880
605
  }
881
606
  },
882
- __2("After", "elementor")
607
+ __("After", "elementor")
883
608
  )
884
609
  ), /* @__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(
885
610
  Box,
@@ -917,26 +642,180 @@ var DuplicateLabelDialog = ({
917
642
  },
918
643
  /* @__PURE__ */ React2.createElement(EllipsisWithTooltip, { title: modified }, /* @__PURE__ */ React2.createElement(Typography, { variant: "body2", sx: { color: "text.primary" } }, modified))
919
644
  )
920
- ))), /* @__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(
645
+ ))), /* @__PURE__ */ React2.createElement(Box, null, /* @__PURE__ */ React2.createElement(Alert, { severity: "info", size: "small", color: "secondary" }, /* @__PURE__ */ React2.createElement("strong", null, __("Your designs and classes are safe.", "elementor")), __(
921
646
  "Only the prefixes were added. Find them in Class Manager by searching",
922
647
  "elementor"
923
- ), /* @__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"))));
648
+ ), /* @__PURE__ */ React2.createElement("strong", null, DUP_PREFIX)))))), /* @__PURE__ */ React2.createElement(DialogActions, null, /* @__PURE__ */ React2.createElement(Button, { color: "secondary", variant: "text", onClick: handleButtonClick }, __("Go to Class Manager", "elementor")), /* @__PURE__ */ React2.createElement(Button, { color: "secondary", variant: "contained", onClick: closeDialog }, __("Done", "elementor"))));
649
+ };
650
+
651
+ // src/utils/tracking.ts
652
+ import { getMixpanel } from "@elementor/events";
653
+ import { __getState as getState } from "@elementor/store";
654
+ var trackGlobalClasses = async (payload) => {
655
+ const { runAction } = payload;
656
+ const data = await getSanitizedData(payload);
657
+ if (data) {
658
+ track(data);
659
+ if (data.event === "classCreated" && "classId" in data) {
660
+ fireClassApplied(data.classId);
661
+ }
662
+ }
663
+ runAction?.();
664
+ };
665
+ var fireClassApplied = async (classId) => {
666
+ const appliedInfo = await getAppliedInfo(classId);
667
+ track({
668
+ event: "classApplied",
669
+ classId,
670
+ ...appliedInfo,
671
+ totalInstancesAfterApply: 1
672
+ });
673
+ };
674
+ var getSanitizedData = async (payload) => {
675
+ switch (payload.event) {
676
+ case "classApplied":
677
+ if ("classId" in payload && payload.classId) {
678
+ const appliedInfo = await getAppliedInfo(payload.classId);
679
+ return { ...payload, ...appliedInfo };
680
+ }
681
+ break;
682
+ case "classRemoved":
683
+ if ("classId" in payload && payload.classId) {
684
+ const deleteInfo = getRemovedInfo(payload.classId);
685
+ return { ...payload, ...deleteInfo };
686
+ }
687
+ break;
688
+ case "classDeleted":
689
+ if ("classId" in payload && payload.classId) {
690
+ const deleteInfo = await trackDeleteClass(payload.classId);
691
+ return { ...payload, ...deleteInfo };
692
+ }
693
+ break;
694
+ case "classCreated":
695
+ if ("source" in payload && payload.source !== "created") {
696
+ if ("classId" in payload && payload.classId) {
697
+ return { ...payload, classTitle: getCssClass(payload.classId).label };
698
+ }
699
+ }
700
+ return payload;
701
+ case "classStateClicked":
702
+ if ("classId" in payload && payload.classId) {
703
+ return { ...payload, classTitle: getCssClass(payload.classId).label };
704
+ }
705
+ break;
706
+ case "classSyncToV3PopupShown":
707
+ return {
708
+ ...payload,
709
+ interaction_type: "popup_shown",
710
+ target_type: "popup",
711
+ target_name: "sync_to_v3_popup",
712
+ interaction_result: "popup_viewed",
713
+ target_location: "widget_panel",
714
+ location_l1: "class_manager"
715
+ };
716
+ case "classSyncToV3": {
717
+ const classLabel = getCssClass(payload.classId).label;
718
+ const isSync = payload.action === "sync";
719
+ return {
720
+ ...payload,
721
+ interaction_type: "click",
722
+ target_type: classLabel,
723
+ target_name: isSync ? "sync_to_v3" : "unsync_to_v3",
724
+ interaction_result: isSync ? "class_is_synced_to_V3" : "class_is_unsynced_from_V3",
725
+ target_location: "widget_panel",
726
+ location_l1: "class_manager",
727
+ interaction_description: isSync ? `user_synced_${classLabel}_to_v3` : `user_unsync_${classLabel}_from_v3`
728
+ };
729
+ }
730
+ case "classSyncToV3PopupClick": {
731
+ const isSyncAction = payload.action === "sync";
732
+ return {
733
+ ...payload,
734
+ interaction_type: "click",
735
+ target_type: "button",
736
+ target_name: isSyncAction ? "sync_to_v3" : "cancel",
737
+ interaction_result: isSyncAction ? "class_is_synced" : "cancel",
738
+ target_location: "sync_to_v3_popup"
739
+ };
740
+ }
741
+ default:
742
+ return payload;
743
+ }
744
+ };
745
+ var track = (data) => {
746
+ const { dispatchEvent, config } = getMixpanel();
747
+ if (!config?.names?.global_classes?.[data.event]) {
748
+ console.error("Global class tracking event not found", { event: data.event });
749
+ return;
750
+ }
751
+ const name = config.names.global_classes[data.event];
752
+ const { event, ...eventData } = data;
753
+ try {
754
+ dispatchEvent?.(name, {
755
+ event,
756
+ ...eventData
757
+ });
758
+ } catch (error) {
759
+ throw new GlobalClassTrackingError({ cause: error });
760
+ }
761
+ };
762
+ var extractCssClassData = (classId) => {
763
+ const cssClass = getCssClass(classId);
764
+ const classTitle = cssClass.label;
765
+ return { classTitle };
766
+ };
767
+ var getCssClass = (classId) => {
768
+ const state = getState();
769
+ const cssClass = selectClass(state, classId);
770
+ if (cssClass) {
771
+ return cssClass;
772
+ }
773
+ const label = selectClassLabels(state)[classId];
774
+ if (label !== void 0) {
775
+ return placeholderDefinition(classId, label);
776
+ }
777
+ throw new Error(`CSS class with ID ${classId} not found`);
778
+ };
779
+ var trackDeleteClass = async (classId) => {
780
+ const classTitle = getCssClass(classId).label;
781
+ const totalInstances = await getTotalInstancesByCssClassID(classId);
782
+ return { totalInstances, classTitle };
783
+ };
784
+ var getTotalInstancesByCssClassID = async (classId) => {
785
+ const cssClassUsage = await fetchCssClassUsage();
786
+ return cssClassUsage[classId]?.total ?? 1;
787
+ };
788
+ var getAppliedInfo = async (classId) => {
789
+ const { classTitle } = extractCssClassData(classId);
790
+ const totalInstancesAfterApply = await getTotalInstancesByCssClassID(classId) + 1;
791
+ return { classTitle, totalInstancesAfterApply };
792
+ };
793
+ var getRemovedInfo = (classId) => {
794
+ const { classTitle } = extractCssClassData(classId);
795
+ return {
796
+ classTitle
797
+ };
924
798
  };
925
799
 
926
800
  // src/save-global-classes.tsx
927
- async function saveGlobalClasses({ context: context2, onApprove }) {
928
- const state = selectData(getState3());
801
+ async function saveGlobalClasses2({ context: context2, onApprove }) {
802
+ const state = selectData(getState2());
929
803
  const apiAction = context2 === "preview" ? apiClient.saveDraft : apiClient.publish;
930
804
  const currentContext = context2 === "preview" ? selectPreviewInitialData : selectFrontendInitialData;
805
+ const changes = calculateChanges(state, currentContext(getState2()));
806
+ const touchedIds = [...changes.added, ...changes.modified];
807
+ const touchedItems = Object.fromEntries(
808
+ touchedIds.map((id2) => [id2, state.items[id2]]).filter(([, v]) => v)
809
+ );
931
810
  const response = await apiAction({
932
- items: state.items,
811
+ items: touchedItems,
933
812
  order: state.order,
934
- changes: calculateChanges(state, currentContext(getState3()))
813
+ changes
935
814
  });
936
- dispatch2(slice.actions.reset({ context: context2 }));
815
+ dispatch(slice.actions.reset({ context: context2 }));
937
816
  window.dispatchEvent(new CustomEvent("classes:updated", { detail: { context: context2 } }));
938
817
  if (response?.data?.data?.code === API_ERROR_CODES.DUPLICATED_LABEL) {
939
- dispatch2(slice.actions.updateMultiple(response.data.data.modifiedLabels));
818
+ dispatch(slice.actions.updateMultiple(response.data.data.modifiedLabels));
940
819
  trackGlobalClasses({
941
820
  event: "classPublishConflict",
942
821
  numOfConflicts: Object.keys(response.data.data.modifiedLabels).length
@@ -955,19 +834,23 @@ async function saveGlobalClasses({ context: context2, onApprove }) {
955
834
  function calculateChanges(state, initialData) {
956
835
  const stateIds = Object.keys(state.items);
957
836
  const initialDataIds = Object.keys(initialData.items);
837
+ const { order: stateOrder } = state;
838
+ const { order: initialDataOrder } = initialData;
839
+ const order = stateOrder.join(";") !== initialDataOrder.join(";");
958
840
  return {
959
841
  added: stateIds.filter((id2) => !initialDataIds.includes(id2)),
960
842
  deleted: initialDataIds.filter((id2) => !stateIds.includes(id2)),
961
843
  modified: stateIds.filter((id2) => {
962
844
  return id2 in initialData.items && hash(state.items[id2]) !== hash(initialData.items[id2]);
963
- })
845
+ }),
846
+ order
964
847
  };
965
848
  }
966
849
 
967
850
  // src/components/search-and-filter/components/filter/active-filters.tsx
968
851
  import * as React6 from "react";
969
852
  import { Chip as Chip2, Stack as Stack3 } from "@elementor/ui";
970
- import { __ as __4 } from "@wordpress/i18n";
853
+ import { __ as __3 } from "@wordpress/i18n";
971
854
 
972
855
  // src/components/search-and-filter/components/filter/clear-icon-button.tsx
973
856
  import * as React4 from "react";
@@ -998,11 +881,11 @@ var CustomIconButton = styled(IconButton)(({ theme }) => ({
998
881
  // src/components/search-and-filter/components/filter/filter-list.tsx
999
882
  import * as React5 from "react";
1000
883
  import { Checkbox, Chip, MenuItem, MenuList, Stack as Stack2, Typography as Typography2 } from "@elementor/ui";
1001
- import { __ as __3 } from "@wordpress/i18n";
884
+ import { __ as __2 } from "@wordpress/i18n";
1002
885
  var filterConfig = {
1003
- unused: __3("Unused", "elementor"),
1004
- empty: __3("Empty", "elementor"),
1005
- onThisPage: __3("On this page", "elementor")
886
+ unused: __2("Unused", "elementor"),
887
+ empty: __2("Empty", "elementor"),
888
+ onThisPage: __2("On this page", "elementor")
1006
889
  };
1007
890
  var FilterList = () => {
1008
891
  const {
@@ -1085,7 +968,7 @@ var ActiveFilters = () => {
1085
968
  ClearIconButton,
1086
969
  {
1087
970
  trigger: "header",
1088
- tooltipText: __4("Clear Filters", "elementor"),
971
+ tooltipText: __3("Clear Filters", "elementor"),
1089
972
  sx: { margin: "0 0 auto auto" }
1090
973
  }
1091
974
  ));
@@ -1106,7 +989,7 @@ import { useEffect } from "react";
1106
989
  import { PopoverBody, PopoverHeader } from "@elementor/editor-ui";
1107
990
  import { FilterIcon } from "@elementor/icons";
1108
991
  import { bindPopover, bindToggle, Divider as Divider2, Popover, ToggleButton, Tooltip as Tooltip2, usePopupState } from "@elementor/ui";
1109
- import { __ as __5 } from "@wordpress/i18n";
992
+ import { __ as __4 } from "@wordpress/i18n";
1110
993
  var CssClassFilter = () => {
1111
994
  const {
1112
995
  filters: { filters }
@@ -1123,7 +1006,7 @@ var CssClassFilter = () => {
1123
1006
  }
1124
1007
  }, [popupState.isOpen]);
1125
1008
  const showCleanIcon = Object.values(filters).some((value) => value);
1126
- return /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(Tooltip2, { title: __5("Filters", "elementor"), placement: "top" }, /* @__PURE__ */ React7.createElement(
1009
+ return /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(Tooltip2, { title: __4("Filters", "elementor"), placement: "top" }, /* @__PURE__ */ React7.createElement(
1127
1010
  ToggleButton,
1128
1011
  {
1129
1012
  value: "filter",
@@ -1157,12 +1040,12 @@ var CssClassFilter = () => {
1157
1040
  {
1158
1041
  trigger: "menu",
1159
1042
  key: "clear-all-button",
1160
- tooltipText: __5("Clear all", "elementor")
1043
+ tooltipText: __4("Clear all", "elementor")
1161
1044
  }
1162
1045
  )
1163
1046
  ] : [],
1164
1047
  onClose: popupState.close,
1165
- title: __5("Filters", "elementor"),
1048
+ title: __4("Filters", "elementor"),
1166
1049
  icon: /* @__PURE__ */ React7.createElement(FilterIcon, { fontSize: "tiny" })
1167
1050
  }
1168
1051
  ),
@@ -1182,7 +1065,7 @@ var CssClassFilter = () => {
1182
1065
  import * as React8 from "react";
1183
1066
  import { SearchIcon } from "@elementor/icons";
1184
1067
  import { Box as Box3, InputAdornment, Stack as Stack4, TextField } from "@elementor/ui";
1185
- import { __ as __6 } from "@wordpress/i18n";
1068
+ import { __ as __5 } from "@wordpress/i18n";
1186
1069
  var ClassManagerSearch = () => {
1187
1070
  const {
1188
1071
  search: { inputValue, handleChange }
@@ -1199,7 +1082,7 @@ var ClassManagerSearch = () => {
1199
1082
  event: "classManagerSearched"
1200
1083
  });
1201
1084
  },
1202
- placeholder: __6("Search", "elementor"),
1085
+ placeholder: __5("Search", "elementor"),
1203
1086
  onChange: (e) => handleChange(e.target.value),
1204
1087
  InputProps: {
1205
1088
  startAdornment: /* @__PURE__ */ React8.createElement(InputAdornment, { position: "start" }, /* @__PURE__ */ React8.createElement(SearchIcon, { fontSize: "tiny" }))
@@ -1214,7 +1097,7 @@ import { useState as useState2 } from "react";
1214
1097
  import { useSuppressedMessage } from "@elementor/editor-current-user";
1215
1098
  import { IntroductionModal } from "@elementor/editor-ui";
1216
1099
  import { Box as Box4, Image, Typography as Typography3 } from "@elementor/ui";
1217
- import { __ as __7 } from "@wordpress/i18n";
1100
+ import { __ as __6 } from "@wordpress/i18n";
1218
1101
  var MESSAGE_KEY = "global-class-manager";
1219
1102
  var ClassManagerIntroduction = () => {
1220
1103
  const [isMessageSuppressed, suppressMessage] = useSuppressedMessage(MESSAGE_KEY);
@@ -1223,7 +1106,7 @@ var ClassManagerIntroduction = () => {
1223
1106
  IntroductionModal,
1224
1107
  {
1225
1108
  open: shouldShowIntroduction,
1226
- title: __7("Class Manager", "elementor"),
1109
+ title: __6("Class Manager", "elementor"),
1227
1110
  handleClose: (shouldShowAgain) => {
1228
1111
  if (!shouldShowAgain) {
1229
1112
  suppressMessage();
@@ -1243,24 +1126,24 @@ var ClassManagerIntroduction = () => {
1243
1126
  );
1244
1127
  };
1245
1128
  var IntroductionContent = () => {
1246
- return /* @__PURE__ */ React9.createElement(Box4, { p: 3 }, /* @__PURE__ */ React9.createElement(Typography3, { variant: "body2" }, __7(
1129
+ return /* @__PURE__ */ React9.createElement(Box4, { p: 3 }, /* @__PURE__ */ React9.createElement(Typography3, { variant: "body2" }, __6(
1247
1130
  "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.",
1248
1131
  "elementor"
1249
- )), /* @__PURE__ */ React9.createElement("br", null), /* @__PURE__ */ React9.createElement(Typography3, { variant: "body2" }, __7(
1132
+ )), /* @__PURE__ */ React9.createElement("br", null), /* @__PURE__ */ React9.createElement(Typography3, { variant: "body2" }, __6(
1250
1133
  "Remember, when editing an item within a specific class, any changes you make will apply across all elements in that class.",
1251
1134
  "elementor"
1252
1135
  )));
1253
1136
  };
1254
1137
 
1255
1138
  // src/components/class-manager/delete-class.ts
1256
- import { __dispatch as dispatch3 } from "@elementor/store";
1139
+ import { __dispatch as dispatch2 } from "@elementor/store";
1257
1140
  var isDeleted = false;
1258
1141
  var deleteClass = (id2) => {
1259
1142
  trackGlobalClasses({
1260
1143
  event: "classDeleted",
1261
1144
  classId: id2,
1262
1145
  runAction: () => {
1263
- dispatch3(slice.actions.delete(id2));
1146
+ dispatch2(slice.actions.delete(id2));
1264
1147
  isDeleted = true;
1265
1148
  }
1266
1149
  });
@@ -1280,7 +1163,8 @@ import * as React17 from "react";
1280
1163
  import { useEffect as useEffect2, useMemo as useMemo3, useState as useState5 } from "react";
1281
1164
  import { __useDispatch as useDispatch } from "@elementor/store";
1282
1165
  import { List, Stack as Stack8, styled as styled6, Typography as Typography8 } from "@elementor/ui";
1283
- import { __ as __13 } from "@wordpress/i18n";
1166
+ import { defaultRangeExtractor, useVirtualizer } from "@tanstack/react-virtual";
1167
+ import { __ as __12 } from "@wordpress/i18n";
1284
1168
 
1285
1169
  // src/hooks/use-ordered-classes.ts
1286
1170
  import { __useSelector as useSelector3 } from "@elementor/store";
@@ -1307,7 +1191,7 @@ import {
1307
1191
  Typography as Typography6,
1308
1192
  usePopupState as usePopupState3
1309
1193
  } from "@elementor/ui";
1310
- import { __ as __11 } from "@wordpress/i18n";
1194
+ import { __ as __10 } from "@wordpress/i18n";
1311
1195
 
1312
1196
  // src/components/css-class-usage/components/css-class-usage-popover.tsx
1313
1197
  import * as React11 from "react";
@@ -1328,7 +1212,7 @@ import {
1328
1212
  PostTypeIcon
1329
1213
  } from "@elementor/icons";
1330
1214
  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";
1331
- import { __ as __8 } from "@wordpress/i18n";
1215
+ import { __ as __7 } from "@wordpress/i18n";
1332
1216
 
1333
1217
  // src/hooks/use-css-class-usage-by-id.ts
1334
1218
  var EMPTY_CLASS_USAGE = {
@@ -1344,23 +1228,23 @@ var useCssClassUsageByID = (id2) => {
1344
1228
  // src/components/css-class-usage/components/css-class-usage-popover.tsx
1345
1229
  var iconMapper = {
1346
1230
  "wp-post": {
1347
- label: __8("Post", "elementor"),
1231
+ label: __7("Post", "elementor"),
1348
1232
  icon: /* @__PURE__ */ React11.createElement(PostTypeIcon, { fontSize: "inherit" })
1349
1233
  },
1350
1234
  "wp-page": {
1351
- label: __8("Page", "elementor"),
1235
+ label: __7("Page", "elementor"),
1352
1236
  icon: /* @__PURE__ */ React11.createElement(PagesIcon, { fontSize: "inherit" })
1353
1237
  },
1354
1238
  popup: {
1355
- label: __8("Popup", "elementor"),
1239
+ label: __7("Popup", "elementor"),
1356
1240
  icon: /* @__PURE__ */ React11.createElement(PopupTemplateIcon, { fontSize: "inherit" })
1357
1241
  },
1358
1242
  header: {
1359
- label: __8("Header", "elementor"),
1243
+ label: __7("Header", "elementor"),
1360
1244
  icon: /* @__PURE__ */ React11.createElement(HeaderTemplateIcon, { fontSize: "inherit" })
1361
1245
  },
1362
1246
  footer: {
1363
- label: __8("Footer", "elementor"),
1247
+ label: __7("Footer", "elementor"),
1364
1248
  icon: /* @__PURE__ */ React11.createElement(FooterTemplateIcon, { fontSize: "inherit" })
1365
1249
  }
1366
1250
  };
@@ -1390,7 +1274,7 @@ var CssClassUsagePopover = ({
1390
1274
  PopoverHeader2,
1391
1275
  {
1392
1276
  icon: /* @__PURE__ */ React11.createElement(CurrentLocationIcon, { fontSize: "tiny" }),
1393
- 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 }))),
1277
+ title: /* @__PURE__ */ React11.createElement(Stack5, { flexDirection: "row", gap: 1, alignItems: "center" }, /* @__PURE__ */ React11.createElement(Box5, { "aria-label": "header-title" }, __7("Locator", "elementor")), /* @__PURE__ */ React11.createElement(Box5, null, /* @__PURE__ */ React11.createElement(Chip3, { sx: { lineHeight: 1 }, size: "tiny", label: classUsage.total }))),
1394
1278
  onClose
1395
1279
  }
1396
1280
  ), /* @__PURE__ */ React11.createElement(Divider3, null), /* @__PURE__ */ React11.createElement(PopoverBody2, { width: 300 }, /* @__PURE__ */ React11.createElement(
@@ -1481,7 +1365,7 @@ import {
1481
1365
  Tooltip as Tooltip4,
1482
1366
  usePopupState as usePopupState2
1483
1367
  } from "@elementor/ui";
1484
- import { __ as __9 } from "@wordpress/i18n";
1368
+ import { __ as __8 } from "@wordpress/i18n";
1485
1369
  var CssClassUsageTrigger = ({ id: id2, onClick }) => {
1486
1370
  const {
1487
1371
  data: { total },
@@ -1562,9 +1446,9 @@ var TooltipWrapper = ({ children, total }) => /* @__PURE__ */ React12.createElem
1562
1446
  {
1563
1447
  disableInteractive: true,
1564
1448
  placement: "top",
1565
- title: `${__9("Show {{number}} {{locations}}", "elementor").replace("{{number}}", total.toString()).replace(
1449
+ title: `${__8("Show {{number}} {{locations}}", "elementor").replace("{{number}}", total.toString()).replace(
1566
1450
  "{{locations}}",
1567
- total === 1 ? __9("location", "elementor") : __9("locations", "elementor")
1451
+ total === 1 ? __8("location", "elementor") : __8("locations", "elementor")
1568
1452
  )}`
1569
1453
  },
1570
1454
  /* @__PURE__ */ React12.createElement("span", null, children)
@@ -1575,7 +1459,7 @@ var InfoAlertMessage = ({ children }) => /* @__PURE__ */ React12.createElement(
1575
1459
  disableInteractive: true,
1576
1460
  placement: "top",
1577
1461
  color: "secondary",
1578
- content: /* @__PURE__ */ React12.createElement(InfoAlert, { sx: { mt: 1 } }, __9("This class isn\u2019t being used yet.", "elementor"))
1462
+ content: /* @__PURE__ */ React12.createElement(InfoAlert, { sx: { mt: 1 } }, __8("This class isn\u2019t being used yet.", "elementor"))
1579
1463
  },
1580
1464
  /* @__PURE__ */ React12.createElement("span", null, children)
1581
1465
  );
@@ -1585,7 +1469,7 @@ import * as React13 from "react";
1585
1469
  import { createContext as createContext2, useContext as useContext2, useState as useState3 } from "react";
1586
1470
  import { ConfirmationDialog } from "@elementor/editor-ui";
1587
1471
  import { Typography as Typography5 } from "@elementor/ui";
1588
- import { __ as __10 } from "@wordpress/i18n";
1472
+ import { __ as __9 } from "@wordpress/i18n";
1589
1473
  var context = createContext2(null);
1590
1474
  var DeleteConfirmationProvider = ({ children }) => {
1591
1475
  const [dialogProps, setDialogProps] = useState3(null);
@@ -1606,14 +1490,14 @@ var DeleteClassDialog = ({ label, id: id2 }) => {
1606
1490
  closeDialog2();
1607
1491
  deleteClass(id2);
1608
1492
  };
1609
- const text = total && content.length ? __10(
1493
+ const text = total && content.length ? __9(
1610
1494
  "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.",
1611
1495
  "elementor"
1612
- ).replace("%1", total.toString()).replace("%2", content.length.toString()) : __10(
1496
+ ).replace("%1", total.toString()).replace("%2", content.length.toString()) : __9(
1613
1497
  "Will permanently remove it from your project and may affect the design across all elements using it. This action cannot be undone.",
1614
1498
  "elementor"
1615
1499
  );
1616
- return /* @__PURE__ */ React13.createElement(ConfirmationDialog, { open: true, onClose: closeDialog2 }, /* @__PURE__ */ React13.createElement(ConfirmationDialog.Title, null, __10("Delete this class?", "elementor")), /* @__PURE__ */ React13.createElement(ConfirmationDialog.Content, null, /* @__PURE__ */ React13.createElement(ConfirmationDialog.ContentText, null, __10("Deleting", "elementor"), /* @__PURE__ */ React13.createElement(Typography5, { variant: "subtitle2", component: "span" }, "\xA0", label, "\xA0"), text)), /* @__PURE__ */ React13.createElement(ConfirmationDialog.Actions, { onClose: closeDialog2, onConfirm: handleConfirm }));
1500
+ return /* @__PURE__ */ React13.createElement(ConfirmationDialog, { open: true, onClose: closeDialog2 }, /* @__PURE__ */ React13.createElement(ConfirmationDialog.Title, null, __9("Delete this class?", "elementor")), /* @__PURE__ */ React13.createElement(ConfirmationDialog.Content, null, /* @__PURE__ */ React13.createElement(ConfirmationDialog.ContentText, null, __9("Deleting", "elementor"), /* @__PURE__ */ React13.createElement(Typography5, { variant: "subtitle2", component: "span" }, "\xA0", label, "\xA0"), text)), /* @__PURE__ */ React13.createElement(ConfirmationDialog.Actions, { onClose: closeDialog2, onConfirm: handleConfirm }));
1617
1501
  };
1618
1502
  var useDeleteConfirmation = () => {
1619
1503
  const contextValue = useContext2(context);
@@ -1632,9 +1516,17 @@ import {
1632
1516
  UnstableSortableItem,
1633
1517
  UnstableSortableProvider
1634
1518
  } from "@elementor/ui";
1635
- var SortableProvider = (props) => /* @__PURE__ */ React14.createElement(UnstableSortableProvider, { restrictAxis: true, variant: "static", dragPlaceholderStyle: { opacity: "1" }, ...props });
1519
+ var SortableProvider = (props) => /* @__PURE__ */ React14.createElement(
1520
+ UnstableSortableProvider,
1521
+ {
1522
+ restrictAxis: true,
1523
+ variant: "static",
1524
+ dragPlaceholderStyle: { visibility: "hidden" },
1525
+ ...props
1526
+ }
1527
+ );
1636
1528
  var SortableTrigger = (props) => /* @__PURE__ */ React14.createElement(StyledSortableTrigger, { ...props, role: "button", className: "class-item-sortable-trigger", "aria-label": "sort" }, /* @__PURE__ */ React14.createElement(GripVerticalIcon, { fontSize: "tiny" }));
1637
- var SortableItem = ({ children, id: id2, ...props }) => {
1529
+ var SortableItem = ({ children, id: id2, style, ...props }) => {
1638
1530
  return /* @__PURE__ */ React14.createElement(
1639
1531
  UnstableSortableItem,
1640
1532
  {
@@ -1655,7 +1547,7 @@ var SortableItem = ({ children, id: id2, ...props }) => {
1655
1547
  Box7,
1656
1548
  {
1657
1549
  ...itemProps,
1658
- style: itemStyle,
1550
+ style: { ...itemStyle, ...!isDragOverlay ? style : null },
1659
1551
  component: "li",
1660
1552
  role: "listitem",
1661
1553
  sx: {
@@ -1759,7 +1651,7 @@ var ClassItem = ({
1759
1651
  {
1760
1652
  placement: "top",
1761
1653
  className: "class-item-more-actions",
1762
- title: __11("More actions", "elementor")
1654
+ title: __10("More actions", "elementor")
1763
1655
  },
1764
1656
  /* @__PURE__ */ React15.createElement(IconButton3, { size: "tiny", ...bindTrigger2(popupState), "aria-label": "More actions" }, /* @__PURE__ */ React15.createElement(DotsVerticalIcon, { fontSize: "tiny" }))
1765
1657
  )
@@ -1786,7 +1678,7 @@ var ClassItem = ({
1786
1678
  openEditMode();
1787
1679
  }
1788
1680
  },
1789
- /* @__PURE__ */ React15.createElement(Typography6, { variant: "caption", sx: { color: "text.primary" } }, __11("Rename", "elementor"))
1681
+ /* @__PURE__ */ React15.createElement(Typography6, { variant: "caption", sx: { color: "text.primary" } }, __10("Rename", "elementor"))
1790
1682
  ),
1791
1683
  onToggleSync && /* @__PURE__ */ React15.createElement(
1792
1684
  MenuListItem,
@@ -1796,7 +1688,7 @@ var ClassItem = ({
1796
1688
  onToggleSync(id2, !syncToV3);
1797
1689
  }
1798
1690
  },
1799
- /* @__PURE__ */ React15.createElement(Stack6, { direction: "row", alignItems: "center", gap: 1 }, syncToV3 ? /* @__PURE__ */ React15.createElement(RefreshOffIcon, { fontSize: "tiny" }) : /* @__PURE__ */ React15.createElement(RefreshIcon, { fontSize: "tiny" }), /* @__PURE__ */ React15.createElement(Typography6, { variant: "caption", sx: { color: "text.primary" } }, syncToV3 ? __11("Stop syncing to Global Fonts", "elementor") : __11("Sync to Global Fonts", "elementor")))
1691
+ /* @__PURE__ */ React15.createElement(Stack6, { direction: "row", alignItems: "center", gap: 1 }, syncToV3 ? /* @__PURE__ */ React15.createElement(RefreshOffIcon, { fontSize: "tiny" }) : /* @__PURE__ */ React15.createElement(RefreshIcon, { fontSize: "tiny" }), /* @__PURE__ */ React15.createElement(Typography6, { variant: "caption", sx: { color: "text.primary" } }, syncToV3 ? __10("Stop syncing to Global Fonts", "elementor") : __10("Sync to Global Fonts", "elementor")))
1800
1692
  ),
1801
1693
  /* @__PURE__ */ React15.createElement(
1802
1694
  MenuListItem,
@@ -1806,7 +1698,7 @@ var ClassItem = ({
1806
1698
  openDialog2({ id: id2, label });
1807
1699
  }
1808
1700
  },
1809
- /* @__PURE__ */ React15.createElement(Typography6, { variant: "caption", sx: { color: "error.light" } }, __11("Delete", "elementor"))
1701
+ /* @__PURE__ */ React15.createElement(Typography6, { variant: "caption", sx: { color: "error.light" } }, __10("Delete", "elementor"))
1810
1702
  )
1811
1703
  ));
1812
1704
  };
@@ -1872,7 +1764,7 @@ var validateLabel = (newLabel) => {
1872
1764
  import * as React16 from "react";
1873
1765
  import { ColorSwatchIcon as ColorSwatchIcon2, PhotoIcon } from "@elementor/icons";
1874
1766
  import { Box as Box9, Link, Stack as Stack7, Typography as Typography7 } from "@elementor/ui";
1875
- import { __ as __12 } from "@wordpress/i18n";
1767
+ import { __ as __11 } from "@wordpress/i18n";
1876
1768
  var getNotFoundType = (searchValue, filters, filteredClasses) => {
1877
1769
  const searchNotFound = filteredClasses.length <= 0 && searchValue.length > 1;
1878
1770
  const filterNotFound = filters && filters.length === 0;
@@ -1890,18 +1782,18 @@ var getNotFoundType = (searchValue, filters, filteredClasses) => {
1890
1782
  };
1891
1783
  var notFound = {
1892
1784
  filterAndSearch: {
1893
- mainText: __12("Sorry, nothing matched.", "elementor"),
1894
- sceneryText: __12("Try something else.", "elementor"),
1785
+ mainText: __11("Sorry, nothing matched.", "elementor"),
1786
+ sceneryText: __11("Try something else.", "elementor"),
1895
1787
  icon: /* @__PURE__ */ React16.createElement(PhotoIcon, { color: "inherit", fontSize: "large" })
1896
1788
  },
1897
1789
  search: {
1898
- mainText: __12("Sorry, nothing matched", "elementor"),
1899
- sceneryText: __12("Clear your input and try something else.", "elementor"),
1790
+ mainText: __11("Sorry, nothing matched", "elementor"),
1791
+ sceneryText: __11("Clear your input and try something else.", "elementor"),
1900
1792
  icon: /* @__PURE__ */ React16.createElement(PhotoIcon, { color: "inherit", fontSize: "large" })
1901
1793
  },
1902
1794
  filter: {
1903
- mainText: __12("Sorry, nothing matched that search.", "elementor"),
1904
- sceneryText: __12("Clear the filters and try something else.", "elementor"),
1795
+ mainText: __11("Sorry, nothing matched that search.", "elementor"),
1796
+ sceneryText: __11("Clear the filters and try something else.", "elementor"),
1905
1797
  icon: /* @__PURE__ */ React16.createElement(ColorSwatchIcon2, { color: "inherit", fontSize: "large" })
1906
1798
  }
1907
1799
  };
@@ -1974,38 +1866,65 @@ var NotFoundLayout = ({ onClear, searchValue, mainText, sceneryText, icon }) =>
1974
1866
  )
1975
1867
  ),
1976
1868
  /* @__PURE__ */ React16.createElement(Typography7, { align: "center", variant: "caption", color: "inherit" }, sceneryText),
1977
- /* @__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")))
1869
+ /* @__PURE__ */ React16.createElement(Typography7, { align: "center", variant: "caption", color: "inherit" }, /* @__PURE__ */ React16.createElement(Link, { color: "secondary", variant: "caption", component: "button", onClick: onClear }, __11("Clear & try again", "elementor")))
1978
1870
  );
1979
1871
 
1980
1872
  // src/components/class-manager/global-classes-list.tsx
1981
- var GlobalClassesList = ({ disabled, onStopSyncRequest, onStartSyncRequest }) => {
1873
+ var ROW_HEIGHT = 40;
1874
+ var OVERSCAN = 6;
1875
+ var GlobalClassesList = ({
1876
+ disabled,
1877
+ scrollElement,
1878
+ onStopSyncRequest,
1879
+ onStartSyncRequest
1880
+ }) => {
1982
1881
  const {
1983
1882
  search: { debouncedValue: searchValue }
1984
1883
  } = useSearchAndFilters();
1985
1884
  const cssClasses = useOrderedClasses();
1986
- const dispatch5 = useDispatch();
1885
+ const dispatch7 = useDispatch();
1987
1886
  const filters = useFilters();
1988
1887
  const [draggedItemId, setDraggedItemId] = useState5(null);
1989
1888
  const draggedItemLabel = cssClasses.find((cssClass) => cssClass.id === draggedItemId)?.label ?? "";
1990
1889
  const [classesOrder, reorderClasses] = useReorder(draggedItemId, setDraggedItemId, draggedItemLabel ?? "");
1991
1890
  const filteredCssClasses = useFilteredCssClasses();
1891
+ const virtualizer = useVirtualizer({
1892
+ count: filteredCssClasses.length,
1893
+ getScrollElement: () => scrollElement ?? null,
1894
+ estimateSize: () => ROW_HEIGHT,
1895
+ overscan: OVERSCAN,
1896
+ getItemKey: (index) => filteredCssClasses[index].id,
1897
+ // Keep the actively dragged row mounted even when scrolled out of view.
1898
+ // SortableItem unregisters its render on unmount, which would make the
1899
+ // DragOverlay clone disappear mid-drag.
1900
+ rangeExtractor: (range) => {
1901
+ const indices = new Set(defaultRangeExtractor(range));
1902
+ if (draggedItemId) {
1903
+ const draggedItemIndex = filteredCssClasses.findIndex((cssClass) => cssClass.id === draggedItemId);
1904
+ if (draggedItemIndex >= 0) {
1905
+ indices.add(draggedItemIndex);
1906
+ }
1907
+ }
1908
+ return [...indices].sort((a, b) => a - b);
1909
+ }
1910
+ });
1992
1911
  useEffect2(() => {
1993
1912
  const handler2 = (event) => {
1994
1913
  if (event.key === "z" && (event.ctrlKey || event.metaKey)) {
1995
1914
  event.stopImmediatePropagation();
1996
1915
  event.preventDefault();
1997
1916
  if (event.shiftKey) {
1998
- dispatch5(slice.actions.redo());
1917
+ dispatch7(slice.actions.redo());
1999
1918
  return;
2000
1919
  }
2001
- dispatch5(slice.actions.undo());
1920
+ dispatch7(slice.actions.undo());
2002
1921
  }
2003
1922
  };
2004
1923
  window.addEventListener("keydown", handler2, {
2005
1924
  capture: true
2006
1925
  });
2007
1926
  return () => window.removeEventListener("keydown", handler2);
2008
- }, [dispatch5]);
1927
+ }, [dispatch7]);
2009
1928
  if (!cssClasses?.length) {
2010
1929
  return /* @__PURE__ */ React17.createElement(EmptyState, null);
2011
1930
  }
@@ -2015,69 +1934,94 @@ var GlobalClassesList = ({ disabled, onStopSyncRequest, onStartSyncRequest }) =>
2015
1934
  }
2016
1935
  const isFiltersApplied = filters?.length || searchValue;
2017
1936
  const allowSorting = filteredCssClasses.length > 1 && !isFiltersApplied;
2018
- return /* @__PURE__ */ React17.createElement(DeleteConfirmationProvider, null, /* @__PURE__ */ React17.createElement(List, { sx: { display: "flex", flexDirection: "column", gap: 0.5 } }, /* @__PURE__ */ React17.createElement(
2019
- SortableProvider,
1937
+ return /* @__PURE__ */ React17.createElement(DeleteConfirmationProvider, null, /* @__PURE__ */ React17.createElement(
1938
+ List,
2020
1939
  {
2021
- value: classesOrder,
2022
- onChange: reorderClasses,
2023
- disableDragOverlay: !allowSorting
2024
- },
2025
- filteredCssClasses?.map((cssClass) => /* @__PURE__ */ React17.createElement(SortableItem, { key: cssClass.id, id: cssClass.id }, ({ isDragged, isDragPlaceholder, triggerProps, triggerStyle }) => {
2026
- if (isDragged && !draggedItemId) {
2027
- setDraggedItemId(cssClass.id);
1940
+ sx: {
1941
+ position: "relative",
1942
+ display: "block",
1943
+ height: virtualizer.getTotalSize(),
1944
+ padding: 0
2028
1945
  }
2029
- return /* @__PURE__ */ React17.createElement(
2030
- ClassItem,
2031
- {
2032
- id: cssClass.id,
2033
- label: cssClass.label,
2034
- renameClass: (newLabel) => {
2035
- trackGlobalClasses({
2036
- event: "classRenamed",
2037
- classId: cssClass.id,
2038
- oldValue: cssClass.label,
2039
- newValue: newLabel,
2040
- source: "class-manager"
2041
- });
2042
- dispatch5(
2043
- slice.actions.update({
2044
- style: {
2045
- id: cssClass.id,
2046
- label: newLabel
2047
- }
2048
- })
2049
- );
2050
- },
2051
- selected: isDragged,
2052
- disabled: disabled || isDragPlaceholder,
2053
- sortableTriggerProps: {
2054
- ...triggerProps,
2055
- style: triggerStyle
1946
+ },
1947
+ /* @__PURE__ */ React17.createElement(
1948
+ SortableProvider,
1949
+ {
1950
+ value: classesOrder,
1951
+ onChange: reorderClasses,
1952
+ onDragStart: (event) => setDraggedItemId(event.active.id),
1953
+ onDragEnd: () => setDraggedItemId(null),
1954
+ onDragCancel: () => setDraggedItemId(null),
1955
+ disableDragOverlay: !allowSorting
1956
+ },
1957
+ virtualizer.getVirtualItems().map((virtualRow) => {
1958
+ const cssClass = filteredCssClasses[virtualRow.index];
1959
+ return /* @__PURE__ */ React17.createElement(
1960
+ SortableItem,
1961
+ {
1962
+ key: virtualRow.key,
1963
+ id: cssClass.id,
1964
+ style: {
1965
+ position: "absolute",
1966
+ top: virtualRow.start,
1967
+ left: 0,
1968
+ width: "100%"
1969
+ }
2056
1970
  },
2057
- showSortIndicator: allowSorting,
2058
- syncToV3: cssClass.sync_to_v3,
2059
- onToggleSync: (id2, newValue) => {
2060
- if (!newValue && onStopSyncRequest) {
2061
- onStopSyncRequest(id2);
2062
- } else if (newValue && onStartSyncRequest) {
2063
- onStartSyncRequest(id2);
2064
- } else {
2065
- dispatch5(
2066
- slice.actions.update({
2067
- style: {
2068
- id: id2,
2069
- sync_to_v3: newValue
2070
- }
2071
- })
2072
- );
1971
+ ({ isDragged, isDragPlaceholder, triggerProps, triggerStyle }) => /* @__PURE__ */ React17.createElement(
1972
+ ClassItem,
1973
+ {
1974
+ id: cssClass.id,
1975
+ label: cssClass.label,
1976
+ renameClass: (newLabel) => {
1977
+ trackGlobalClasses({
1978
+ event: "classRenamed",
1979
+ classId: cssClass.id,
1980
+ oldValue: cssClass.label,
1981
+ newValue: newLabel,
1982
+ source: "class-manager"
1983
+ });
1984
+ dispatch7(
1985
+ slice.actions.update({
1986
+ style: {
1987
+ id: cssClass.id,
1988
+ label: newLabel
1989
+ }
1990
+ })
1991
+ );
1992
+ },
1993
+ selected: isDragged,
1994
+ disabled: disabled || isDragPlaceholder,
1995
+ sortableTriggerProps: {
1996
+ ...triggerProps,
1997
+ style: triggerStyle
1998
+ },
1999
+ showSortIndicator: allowSorting,
2000
+ syncToV3: cssClass.sync_to_v3,
2001
+ onToggleSync: (id2, newValue) => {
2002
+ if (!newValue && onStopSyncRequest) {
2003
+ onStopSyncRequest(id2);
2004
+ } else if (newValue && onStartSyncRequest) {
2005
+ onStartSyncRequest(id2);
2006
+ } else {
2007
+ dispatch7(
2008
+ slice.actions.update({
2009
+ style: {
2010
+ id: id2,
2011
+ sync_to_v3: newValue
2012
+ }
2013
+ })
2014
+ );
2015
+ }
2016
+ }
2073
2017
  }
2074
- }
2075
- }
2076
- );
2077
- }))
2078
- )));
2018
+ )
2019
+ );
2020
+ })
2021
+ )
2022
+ ));
2079
2023
  };
2080
- 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(
2024
+ 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" }, __12("There are no global classes yet.", "elementor")), /* @__PURE__ */ React17.createElement(Typography8, { align: "center", variant: "caption", color: "text.secondary" }, __12(
2081
2025
  "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.",
2082
2026
  "elementor"
2083
2027
  )));
@@ -2087,10 +2031,10 @@ var StyledHeader = styled6(Typography8)(({ theme, variant }) => ({
2087
2031
  }
2088
2032
  }));
2089
2033
  var useReorder = (draggedItemId, setDraggedItemId, draggedItemLabel) => {
2090
- const dispatch5 = useDispatch();
2034
+ const dispatch7 = useDispatch();
2091
2035
  const order = useClassesOrder();
2092
2036
  const reorder = (newIds) => {
2093
- dispatch5(slice.actions.setOrder(newIds));
2037
+ dispatch7(slice.actions.setOrder(newIds));
2094
2038
  if (draggedItemId) {
2095
2039
  trackGlobalClasses({
2096
2040
  event: "classManagerReorder",
@@ -2152,7 +2096,7 @@ import {
2152
2096
  FormControlLabel,
2153
2097
  Typography as Typography9
2154
2098
  } from "@elementor/ui";
2155
- import { __ as __14 } from "@wordpress/i18n";
2099
+ import { __ as __13 } from "@wordpress/i18n";
2156
2100
  var IMAGE_URL = "https://assets.elementor.com/packages/v1/images/class-manager-sync-modal.png";
2157
2101
  var StartSyncToV3Modal = ({
2158
2102
  externalOpen,
@@ -2184,7 +2128,7 @@ var StartSyncToV3Modal = ({
2184
2128
  onConfirm?.();
2185
2129
  onExternalClose?.();
2186
2130
  };
2187
- return /* @__PURE__ */ React18.createElement(Dialog, { open: !!externalOpen, onClose: handleClose, maxWidth: "sm", fullWidth: true }, /* @__PURE__ */ React18.createElement(DialogContent2, { sx: { p: 0 } }, /* @__PURE__ */ React18.createElement(Box10, { component: "img", src: IMAGE_URL, alt: "", sx: { width: "100%", display: "block" } }), /* @__PURE__ */ React18.createElement(Box10, { sx: { px: 3, pt: 4, pb: 1 } }, /* @__PURE__ */ React18.createElement(Typography9, { variant: "h6" }, __14("Sync class to Global Fonts", "elementor")), /* @__PURE__ */ React18.createElement(Typography9, { variant: "body2", color: "secondary", sx: { mb: 2, pt: 1 } }, __14(
2131
+ return /* @__PURE__ */ React18.createElement(Dialog, { open: !!externalOpen, onClose: handleClose, maxWidth: "sm", fullWidth: true }, /* @__PURE__ */ React18.createElement(DialogContent2, { sx: { p: 0 } }, /* @__PURE__ */ React18.createElement(Box10, { component: "img", src: IMAGE_URL, alt: "", sx: { width: "100%", display: "block" } }), /* @__PURE__ */ React18.createElement(Box10, { sx: { px: 3, pt: 4, pb: 1 } }, /* @__PURE__ */ React18.createElement(Typography9, { variant: "h6" }, __13("Sync class to Global Fonts", "elementor")), /* @__PURE__ */ React18.createElement(Typography9, { variant: "body2", color: "secondary", sx: { mb: 2, pt: 1 } }, __13(
2188
2132
  "Only typography settings supported in Global Fonts will be applied, including: font family, responsive font sizes, weight, text transform, decoration, line height, letter spacing, and word spacing. Changes made in the class will automatically apply to Global Fonts.",
2189
2133
  "elementor"
2190
2134
  )))), /* @__PURE__ */ React18.createElement(DialogActions2, { sx: { justifyContent: "space-between", px: 3, pb: 2 } }, /* @__PURE__ */ React18.createElement(
@@ -2197,24 +2141,27 @@ var StartSyncToV3Modal = ({
2197
2141
  onChange: (e) => setShouldShowAgain(!e.target.checked)
2198
2142
  }
2199
2143
  ),
2200
- label: /* @__PURE__ */ React18.createElement(Typography9, { variant: "body2", color: "secondary" }, __14("Don't show again", "elementor"))
2144
+ label: /* @__PURE__ */ React18.createElement(Typography9, { variant: "body2", color: "secondary" }, __13("Don't show again", "elementor"))
2201
2145
  }
2202
- ), /* @__PURE__ */ React18.createElement(Box10, { sx: { display: "flex", gap: 1 } }, /* @__PURE__ */ React18.createElement(Button2, { onClick: handleClose, color: "secondary", size: "small" }, __14("Cancel", "elementor")), /* @__PURE__ */ React18.createElement(Button2, { onClick: handleConfirm, variant: "contained", size: "small" }, __14("Sync to Global Fonts", "elementor")))));
2146
+ ), /* @__PURE__ */ React18.createElement(Box10, { sx: { display: "flex", gap: 1 } }, /* @__PURE__ */ React18.createElement(Button2, { onClick: handleClose, color: "secondary", size: "small" }, __13("Cancel", "elementor")), /* @__PURE__ */ React18.createElement(Button2, { onClick: handleConfirm, variant: "contained", size: "small" }, __13("Sync to Global Fonts", "elementor")))));
2203
2147
  };
2204
2148
 
2205
2149
  // src/components/class-manager/class-manager-panel.tsx
2206
2150
  var STOP_SYNC_MESSAGE_KEY = "stop-sync-class";
2207
2151
  var id = "global-classes-manager";
2208
- var reloadDocument = () => {
2209
- const currentDocument = getCurrentDocument();
2210
- const documentsManager = getV1DocumentsManager();
2211
- documentsManager.invalidateCache();
2212
- return runCommand("editor/documents/switch", {
2213
- id: currentDocument?.id,
2214
- shouldScroll: false,
2215
- shouldNavigateToDefaultRoute: false
2216
- });
2217
- };
2152
+ function ClassManagerPanelEmbedded({ onRequestClose, onExposeCloseAttempt }) {
2153
+ return /* @__PURE__ */ React19.createElement(
2154
+ ClassManagerPanelRoot,
2155
+ {
2156
+ embedded: true,
2157
+ onRequestClose,
2158
+ onExposeCloseAttempt
2159
+ }
2160
+ );
2161
+ }
2162
+ function ClassManagerPanel() {
2163
+ return /* @__PURE__ */ React19.createElement(ClassManagerPanelRoot, null);
2164
+ }
2218
2165
  var { panel, usePanelActions } = createPanel({
2219
2166
  id,
2220
2167
  component: ClassManagerPanel,
@@ -2225,25 +2172,58 @@ var { panel, usePanelActions } = createPanel({
2225
2172
  },
2226
2173
  onClose: async () => {
2227
2174
  changeEditMode("edit");
2228
- await reloadDocument();
2175
+ await reloadCurrentDocument();
2229
2176
  unblockPanelInteractions();
2230
2177
  },
2231
2178
  isOpenPreviousElement: true
2232
2179
  });
2233
- function ClassManagerPanel() {
2180
+ function ClassManagerPanelRoot({
2181
+ embedded = false,
2182
+ onRequestClose,
2183
+ onExposeCloseAttempt
2184
+ } = {}) {
2234
2185
  const isDirty2 = useDirtyState();
2235
- const { close: closePanel } = usePanelActions();
2186
+ const { close: closeStandalonePanel } = usePanelActions();
2187
+ const closePanel = useMemo4(
2188
+ () => embedded ? onRequestClose ?? (async () => {
2189
+ }) : closeStandalonePanel,
2190
+ [embedded, onRequestClose, closeStandalonePanel]
2191
+ );
2236
2192
  const { open: openSaveChangesDialog, close: closeSaveChangesDialog, isOpen: isSaveChangesDialogOpen } = useDialog();
2237
2193
  const [stopSyncConfirmation, setStopSyncConfirmation] = useState7(null);
2238
2194
  const [startSyncConfirmation, setStartSyncConfirmation] = useState7(null);
2239
2195
  const [isStopSyncSuppressed] = useSuppressedMessage2(STOP_SYNC_MESSAGE_KEY);
2196
+ const [scrollElement, setScrollElement] = useState7(null);
2240
2197
  const { mutateAsync: publish, isPending: isPublishing } = usePublish();
2241
2198
  const resetAndClosePanel = () => {
2242
- dispatch4(slice.actions.resetToInitialState({ context: "frontend" }));
2199
+ dispatch3(slice.actions.resetToInitialState({ context: "frontend" }));
2243
2200
  closeSaveChangesDialog();
2244
2201
  };
2202
+ const handleClosePanel = useCallback(() => {
2203
+ if (isDirty2) {
2204
+ openSaveChangesDialog();
2205
+ return;
2206
+ }
2207
+ void closePanel();
2208
+ }, [isDirty2, openSaveChangesDialog, closePanel]);
2209
+ useEffect4(() => {
2210
+ if (!embedded || !onExposeCloseAttempt) {
2211
+ return;
2212
+ }
2213
+ onExposeCloseAttempt(() => handleClosePanel());
2214
+ return () => onExposeCloseAttempt(null);
2215
+ }, [embedded, onExposeCloseAttempt, handleClosePanel]);
2216
+ useEffect4(() => {
2217
+ if (!embedded) {
2218
+ return;
2219
+ }
2220
+ blockPanelInteractions();
2221
+ return () => {
2222
+ unblockPanelInteractions();
2223
+ };
2224
+ }, [embedded]);
2245
2225
  const handleStopSync = useCallback((classId) => {
2246
- dispatch4(
2226
+ dispatch3(
2247
2227
  slice.actions.update({
2248
2228
  style: {
2249
2229
  id: classId,
@@ -2255,7 +2235,7 @@ function ClassManagerPanel() {
2255
2235
  setStopSyncConfirmation(null);
2256
2236
  }, []);
2257
2237
  const handleStartSync = useCallback((classId) => {
2258
- dispatch4(
2238
+ dispatch3(
2259
2239
  slice.actions.update({
2260
2240
  style: {
2261
2241
  id: classId,
@@ -2277,49 +2257,29 @@ function ClassManagerPanel() {
2277
2257
  [isStopSyncSuppressed, handleStopSync]
2278
2258
  );
2279
2259
  usePreventUnload();
2280
- return /* @__PURE__ */ React19.createElement(ThemeProvider, null, /* @__PURE__ */ React19.createElement(ErrorBoundary, { fallback: /* @__PURE__ */ React19.createElement(ErrorBoundaryFallback, null) }, /* @__PURE__ */ React19.createElement(Panel, null, /* @__PURE__ */ React19.createElement(SearchAndFilterProvider, null, /* @__PURE__ */ React19.createElement(PanelHeader, null, /* @__PURE__ */ React19.createElement(Stack9, { p: 1, pl: 2, width: "100%", direction: "row", alignItems: "center" }, /* @__PURE__ */ React19.createElement(Stack9, { width: "100%", direction: "row", gap: 1 }, /* @__PURE__ */ React19.createElement(PanelHeaderTitle, { sx: { display: "flex", alignItems: "center", gap: 0.5 } }, /* @__PURE__ */ React19.createElement(FlippedColorSwatchIcon, { fontSize: "inherit" }), __15("Class Manager", "elementor")), /* @__PURE__ */ React19.createElement(TotalCssClassCounter, null)), /* @__PURE__ */ React19.createElement(
2281
- CloseButton,
2282
- {
2283
- sx: { marginLeft: "auto" },
2284
- disabled: isPublishing,
2285
- onClose: () => {
2286
- if (isDirty2) {
2287
- openSaveChangesDialog();
2288
- return;
2289
- }
2290
- closePanel();
2291
- }
2292
- }
2293
- ))), /* @__PURE__ */ React19.createElement(
2294
- PanelBody,
2260
+ const searchFiltersBlock = /* @__PURE__ */ React19.createElement(Box11, { px: 2, pb: 1 }, /* @__PURE__ */ React19.createElement(Stack9, { direction: "row", alignItems: "center", justifyContent: "space-between", gap: 0.5, sx: { pb: 0.5 } }, /* @__PURE__ */ React19.createElement(Box11, { sx: embedded ? { flexGrow: 1, minWidth: 0 } : { flexGrow: 1 } }, /* @__PURE__ */ React19.createElement(ClassManagerSearch, null)), /* @__PURE__ */ React19.createElement(CssClassFilter, null), embedded && /* @__PURE__ */ React19.createElement(TotalCssClassCounter, null)), /* @__PURE__ */ React19.createElement(ActiveFilters, null));
2261
+ const listArea = /* @__PURE__ */ React19.createElement(
2262
+ Box11,
2295
2263
  {
2264
+ ref: setScrollElement,
2265
+ px: 2,
2296
2266
  sx: {
2297
- display: "flex",
2298
- flexDirection: "column",
2299
- height: "100%"
2267
+ flexGrow: 1,
2268
+ overflowY: "auto",
2269
+ ...embedded ? { minHeight: 0 } : {}
2300
2270
  }
2301
2271
  },
2302
- /* @__PURE__ */ React19.createElement(Box11, { px: 2, pb: 1 }, /* @__PURE__ */ React19.createElement(Stack9, { direction: "row", justifyContent: "spaceBetween", gap: 0.5, sx: { pb: 0.5 } }, /* @__PURE__ */ React19.createElement(Box11, { sx: { flexGrow: 1 } }, /* @__PURE__ */ React19.createElement(ClassManagerSearch, null)), /* @__PURE__ */ React19.createElement(CssClassFilter, null)), /* @__PURE__ */ React19.createElement(ActiveFilters, null)),
2303
- /* @__PURE__ */ React19.createElement(Divider4, null),
2304
2272
  /* @__PURE__ */ React19.createElement(
2305
- Box11,
2273
+ GlobalClassesList,
2306
2274
  {
2307
- px: 2,
2308
- sx: {
2309
- flexGrow: 1,
2310
- overflowY: "auto"
2311
- }
2312
- },
2313
- /* @__PURE__ */ React19.createElement(
2314
- GlobalClassesList,
2315
- {
2316
- disabled: isPublishing,
2317
- onStopSyncRequest: handleStopSyncRequest,
2318
- onStartSyncRequest: (classId) => setStartSyncConfirmation(classId)
2319
- }
2320
- )
2275
+ disabled: isPublishing,
2276
+ scrollElement,
2277
+ onStopSyncRequest: handleStopSyncRequest,
2278
+ onStartSyncRequest: (classId) => setStartSyncConfirmation(classId)
2279
+ }
2321
2280
  )
2322
- ), /* @__PURE__ */ React19.createElement(PanelFooter, null, /* @__PURE__ */ React19.createElement(
2281
+ );
2282
+ const saveFooter = /* @__PURE__ */ React19.createElement(PanelFooter, null, /* @__PURE__ */ React19.createElement(
2323
2283
  Button3,
2324
2284
  {
2325
2285
  fullWidth: true,
@@ -2330,8 +2290,9 @@ function ClassManagerPanel() {
2330
2290
  disabled: !isDirty2,
2331
2291
  loading: isPublishing
2332
2292
  },
2333
- __15("Save changes", "elementor")
2334
- ))))), /* @__PURE__ */ React19.createElement(ClassManagerIntroduction, null), startSyncConfirmation && /* @__PURE__ */ React19.createElement(
2293
+ __14("Save changes", "elementor")
2294
+ ));
2295
+ const dialogs = /* @__PURE__ */ React19.createElement(React19.Fragment, null, startSyncConfirmation && /* @__PURE__ */ React19.createElement(
2335
2296
  StartSyncToV3Modal,
2336
2297
  {
2337
2298
  externalOpen: true,
@@ -2346,30 +2307,84 @@ function ClassManagerPanel() {
2346
2307
  onClose: () => setStopSyncConfirmation(null),
2347
2308
  onConfirm: () => handleStopSync(stopSyncConfirmation)
2348
2309
  }
2349
- ), isSaveChangesDialogOpen && /* @__PURE__ */ React19.createElement(SaveChangesDialog, null, /* @__PURE__ */ React19.createElement(DialogHeader2, { onClose: closeSaveChangesDialog, logo: false }, /* @__PURE__ */ React19.createElement(SaveChangesDialog.Title, null, __15("You have unsaved changes", "elementor"))), /* @__PURE__ */ React19.createElement(SaveChangesDialog.Content, null, /* @__PURE__ */ React19.createElement(SaveChangesDialog.ContentText, null, __15("You have unsaved changes in the Class Manager.", "elementor")), /* @__PURE__ */ React19.createElement(SaveChangesDialog.ContentText, null, __15("To avoid losing your updates, save your changes before leaving.", "elementor"))), /* @__PURE__ */ React19.createElement(
2310
+ ), isSaveChangesDialogOpen && /* @__PURE__ */ React19.createElement(SaveChangesDialog, null, /* @__PURE__ */ React19.createElement(DialogHeader2, { onClose: closeSaveChangesDialog, logo: false }, /* @__PURE__ */ React19.createElement(SaveChangesDialog.Title, null, __14("You have unsaved changes", "elementor"))), /* @__PURE__ */ React19.createElement(SaveChangesDialog.Content, null, /* @__PURE__ */ React19.createElement(SaveChangesDialog.ContentText, null, __14("You have unsaved changes in the Class Manager.", "elementor")), /* @__PURE__ */ React19.createElement(SaveChangesDialog.ContentText, null, __14("To avoid losing your updates, save your changes before leaving.", "elementor"))), /* @__PURE__ */ React19.createElement(
2350
2311
  SaveChangesDialog.Actions,
2351
2312
  {
2352
2313
  actions: {
2353
2314
  discard: {
2354
- label: __15("Discard", "elementor"),
2315
+ label: __14("Discard", "elementor"),
2355
2316
  action: () => {
2356
2317
  resetAndClosePanel();
2357
2318
  }
2358
2319
  },
2359
2320
  confirm: {
2360
- label: __15("Save & Continue", "elementor"),
2321
+ label: __14("Save & Continue", "elementor"),
2361
2322
  action: async () => {
2362
2323
  await publish();
2363
2324
  closeSaveChangesDialog();
2364
- closePanel();
2325
+ void closePanel();
2365
2326
  }
2366
2327
  }
2367
2328
  }
2368
2329
  }
2369
2330
  )));
2331
+ const classManagerLayout = embedded ? /* @__PURE__ */ React19.createElement(
2332
+ Stack9,
2333
+ {
2334
+ direction: "column",
2335
+ sx: {
2336
+ height: "100%",
2337
+ width: "100%",
2338
+ flex: 1,
2339
+ minHeight: 0,
2340
+ overflow: "hidden"
2341
+ }
2342
+ },
2343
+ searchFiltersBlock,
2344
+ /* @__PURE__ */ React19.createElement(Divider4, null),
2345
+ listArea,
2346
+ saveFooter
2347
+ ) : /* @__PURE__ */ React19.createElement(Panel, null, /* @__PURE__ */ React19.createElement(PanelHeader, null, /* @__PURE__ */ React19.createElement(Stack9, { p: 1, pl: 2, width: "100%", direction: "row", alignItems: "center" }, /* @__PURE__ */ React19.createElement(Stack9, { width: "100%", direction: "row", gap: 1 }, /* @__PURE__ */ React19.createElement(PanelHeaderTitle, { sx: { display: "flex", alignItems: "center", gap: 0.5 } }, /* @__PURE__ */ React19.createElement(FlippedColorSwatchIcon, { fontSize: "inherit" }), __14("Class Manager", "elementor")), /* @__PURE__ */ React19.createElement(TotalCssClassCounter, null)), /* @__PURE__ */ React19.createElement(
2348
+ ClassPanelCloseButton,
2349
+ {
2350
+ disabled: isPublishing,
2351
+ onClose: () => {
2352
+ if (isDirty2) {
2353
+ openSaveChangesDialog();
2354
+ return;
2355
+ }
2356
+ void closeStandalonePanel();
2357
+ }
2358
+ }
2359
+ ))), /* @__PURE__ */ React19.createElement(
2360
+ PanelBody,
2361
+ {
2362
+ sx: {
2363
+ display: "flex",
2364
+ flexDirection: "column",
2365
+ height: "100%"
2366
+ }
2367
+ },
2368
+ searchFiltersBlock,
2369
+ /* @__PURE__ */ React19.createElement(Divider4, null),
2370
+ listArea
2371
+ ), saveFooter);
2372
+ const core = /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement(ErrorBoundary, { fallback: /* @__PURE__ */ React19.createElement(ErrorBoundaryFallback, null) }, /* @__PURE__ */ React19.createElement(SearchAndFilterProvider, null, classManagerLayout)), /* @__PURE__ */ React19.createElement(ClassManagerIntroduction, null), dialogs);
2373
+ return embedded ? core : /* @__PURE__ */ React19.createElement(ThemeProvider, null, core);
2370
2374
  }
2371
- var CloseButton = ({ onClose, ...props }) => /* @__PURE__ */ React19.createElement(IconButton4, { size: "small", color: "secondary", onClick: onClose, "aria-label": "Close", ...props }, /* @__PURE__ */ React19.createElement(XIcon, { fontSize: "small" }));
2372
- var ErrorBoundaryFallback = () => /* @__PURE__ */ React19.createElement(Box11, { role: "alert", sx: { minHeight: "100%", p: 2 } }, /* @__PURE__ */ React19.createElement(Alert2, { severity: "error", sx: { mb: 2, maxWidth: 400, textAlign: "center" } }, /* @__PURE__ */ React19.createElement("strong", null, __15("Something went wrong", "elementor"))));
2375
+ var ClassPanelCloseButton = ({ onClose, sx, ...props }) => /* @__PURE__ */ React19.createElement(
2376
+ IconButton4,
2377
+ {
2378
+ size: "small",
2379
+ color: "secondary",
2380
+ onClick: onClose,
2381
+ "aria-label": "Close",
2382
+ sx: { marginLeft: "auto", ...sx },
2383
+ ...props
2384
+ },
2385
+ /* @__PURE__ */ React19.createElement(XIcon, { fontSize: "small" })
2386
+ );
2387
+ var ErrorBoundaryFallback = () => /* @__PURE__ */ React19.createElement(Box11, { role: "alert", sx: { minHeight: "100%", p: 2 } }, /* @__PURE__ */ React19.createElement(Alert2, { severity: "error", sx: { mb: 2, maxWidth: 400, textAlign: "center" } }, /* @__PURE__ */ React19.createElement("strong", null, __14("Something went wrong", "elementor"))));
2373
2388
  var usePreventUnload = () => {
2374
2389
  const isDirty2 = useDirtyState();
2375
2390
  useEffect4(() => {
@@ -2386,7 +2401,7 @@ var usePreventUnload = () => {
2386
2401
  };
2387
2402
  var usePublish = () => {
2388
2403
  return useMutation({
2389
- mutationFn: () => saveGlobalClasses({ context: "frontend" }),
2404
+ mutationFn: () => saveGlobalClasses2({ context: "frontend" }),
2390
2405
  onSuccess: async () => {
2391
2406
  setDocumentModifiedStatus(false);
2392
2407
  if (hasDeletedItems()) {
@@ -2408,7 +2423,7 @@ var TotalCssClassCounter = () => {
2408
2423
  };
2409
2424
  var StopSyncConfirmationDialog = ({ open, onClose, onConfirm }) => {
2410
2425
  const [, suppressStopSyncMessage] = useSuppressedMessage2(STOP_SYNC_MESSAGE_KEY);
2411
- return /* @__PURE__ */ React19.createElement(ConfirmationDialog2, { open, onClose }, /* @__PURE__ */ React19.createElement(ConfirmationDialog2.Title, { icon: FlippedColorSwatchIcon, iconColor: "primary" }, __15("Un-sync typography class", "elementor")), /* @__PURE__ */ React19.createElement(ConfirmationDialog2.Content, null, /* @__PURE__ */ React19.createElement(ConfirmationDialog2.ContentText, null, __15("You're about to stop syncing a typography class to Global Fonts.", "elementor")), /* @__PURE__ */ React19.createElement(ConfirmationDialog2.ContentText, { sx: { mt: 1 } }, __15(
2426
+ return /* @__PURE__ */ React19.createElement(ConfirmationDialog2, { open, onClose }, /* @__PURE__ */ React19.createElement(ConfirmationDialog2.Title, { icon: FlippedColorSwatchIcon, iconColor: "primary" }, __14("Un-sync typography class", "elementor")), /* @__PURE__ */ React19.createElement(ConfirmationDialog2.Content, null, /* @__PURE__ */ React19.createElement(ConfirmationDialog2.ContentText, null, __14("You're about to stop syncing a typography class to Global Fonts.", "elementor")), /* @__PURE__ */ React19.createElement(ConfirmationDialog2.ContentText, { sx: { mt: 1 } }, __14(
2412
2427
  "Note that if it's being used anywhere, the affected elements will inherit the default typography.",
2413
2428
  "elementor"
2414
2429
  ))), /* @__PURE__ */ React19.createElement(
@@ -2416,15 +2431,326 @@ var StopSyncConfirmationDialog = ({ open, onClose, onConfirm }) => {
2416
2431
  {
2417
2432
  onClose,
2418
2433
  onConfirm,
2419
- cancelLabel: __15("Cancel", "elementor"),
2420
- confirmLabel: __15("Got it", "elementor"),
2434
+ cancelLabel: __14("Cancel", "elementor"),
2435
+ confirmLabel: __14("Got it", "elementor"),
2421
2436
  color: "primary",
2422
2437
  onSuppressMessage: suppressStopSyncMessage,
2423
- suppressLabel: __15("Don't show again", "elementor")
2438
+ suppressLabel: __14("Don't show again", "elementor")
2424
2439
  }
2425
2440
  ));
2426
2441
  };
2427
2442
 
2443
+ // src/mcp-integration/classes-resource.ts
2444
+ import { __getState as getState5 } from "@elementor/store";
2445
+
2446
+ // src/global-classes-styles-provider.ts
2447
+ import {
2448
+ generateId
2449
+ } from "@elementor/editor-styles";
2450
+ import { createStylesProvider } from "@elementor/editor-styles-repository";
2451
+ import {
2452
+ __dispatch as dispatch6,
2453
+ __getState as getState4,
2454
+ __subscribeWithSelector as subscribeWithSelector
2455
+ } from "@elementor/store";
2456
+ import { __ as __15 } from "@wordpress/i18n";
2457
+
2458
+ // src/capabilities.ts
2459
+ import { isExperimentActive } from "@elementor/editor-v1-adapters";
2460
+ var EXPERIMENT_KEY = "global_classes_should_enforce_capabilities";
2461
+ var UPDATE_CLASS_CAPABILITY_KEY = "elementor_global_classes_update_class";
2462
+ var getCapabilities = () => {
2463
+ const shouldEnforceCapabilities = isExperimentActive(EXPERIMENT_KEY);
2464
+ if (shouldEnforceCapabilities) {
2465
+ return {
2466
+ update: UPDATE_CLASS_CAPABILITY_KEY,
2467
+ create: UPDATE_CLASS_CAPABILITY_KEY,
2468
+ delete: UPDATE_CLASS_CAPABILITY_KEY,
2469
+ updateProps: UPDATE_CLASS_CAPABILITY_KEY
2470
+ };
2471
+ }
2472
+ };
2473
+
2474
+ // src/load-existing-classes.ts
2475
+ import { __dispatch as dispatch5, __getState as getState3 } from "@elementor/store";
2476
+
2477
+ // src/load-document-classes.ts
2478
+ import { getCurrentDocument } from "@elementor/editor-documents";
2479
+ import { __dispatch as dispatch4 } from "@elementor/store";
2480
+
2481
+ // src/utils/create-labels-for-classes.ts
2482
+ function createLabelsForClasses(entries) {
2483
+ return Object.fromEntries(entries.map((e) => [e.id, e.label]));
2484
+ }
2485
+
2486
+ // src/load-document-classes.ts
2487
+ function styleDefinitionsMapWithoutNull(map) {
2488
+ return Object.fromEntries(
2489
+ Object.entries(map).filter(
2490
+ (entry) => entry[1] !== null
2491
+ )
2492
+ );
2493
+ }
2494
+ function resetGlobalClassesState(globalOrder, classLabels) {
2495
+ dispatch4(
2496
+ slice.actions.load({
2497
+ preview: { items: {}, order: globalOrder },
2498
+ frontend: { items: {}, order: globalOrder },
2499
+ classLabels
2500
+ })
2501
+ );
2502
+ }
2503
+ async function loadCurrentDocumentClasses() {
2504
+ const previewIndexRes = await apiClient.all("preview");
2505
+ const previewIndex = previewIndexRes.data.data;
2506
+ const classLabels = createLabelsForClasses(previewIndex);
2507
+ const globalOrder = previewIndex.map((e) => e.id);
2508
+ resetGlobalClassesState(globalOrder, classLabels);
2509
+ const postId = getCurrentDocument()?.id;
2510
+ if (!postId) {
2511
+ return;
2512
+ }
2513
+ const [previewPostRes, frontendPostRes] = await Promise.all([
2514
+ apiClient.getStylesForPost(postId, "preview"),
2515
+ apiClient.getStylesForPost(postId, "frontend")
2516
+ ]);
2517
+ const previewItems = styleDefinitionsMapWithoutNull(previewPostRes.data.data);
2518
+ const frontendItems = styleDefinitionsMapWithoutNull(frontendPostRes.data.data);
2519
+ dispatch4(
2520
+ slice.actions.load({
2521
+ preview: { items: previewItems, order: globalOrder },
2522
+ frontend: { items: frontendItems, order: globalOrder },
2523
+ classLabels
2524
+ })
2525
+ );
2526
+ }
2527
+ async function addDocumentClasses(documentId) {
2528
+ const [previewPostRes, frontendPostRes] = await Promise.all([
2529
+ apiClient.getStylesForPost(documentId, "preview"),
2530
+ apiClient.getStylesForPost(documentId, "frontend")
2531
+ ]);
2532
+ const previewItems = styleDefinitionsMapWithoutNull(previewPostRes.data.data);
2533
+ const frontendItems = styleDefinitionsMapWithoutNull(frontendPostRes.data.data);
2534
+ dispatch4(
2535
+ slice.actions.mergeExistingClasses({
2536
+ preview: previewItems,
2537
+ frontend: frontendItems
2538
+ })
2539
+ );
2540
+ }
2541
+
2542
+ // src/load-existing-classes.ts
2543
+ var pendingLoad = null;
2544
+ var pendingIds = /* @__PURE__ */ new Set();
2545
+ async function loadExistingClasses(classIds) {
2546
+ const existingClasses = selectGlobalClasses(getState3());
2547
+ const missingIds = classIds.filter((id2) => !(id2 in existingClasses));
2548
+ if (missingIds.length === 0) {
2549
+ return;
2550
+ }
2551
+ missingIds.forEach((id2) => pendingIds.add(id2));
2552
+ if (pendingLoad) {
2553
+ await pendingLoad;
2554
+ return loadExistingClasses(classIds);
2555
+ }
2556
+ pendingLoad = fetchAndMergeClasses();
2557
+ try {
2558
+ await pendingLoad;
2559
+ } finally {
2560
+ pendingLoad = null;
2561
+ }
2562
+ }
2563
+ async function fetchAndMergeClasses() {
2564
+ const idsToFetch = Array.from(pendingIds);
2565
+ pendingIds.clear();
2566
+ if (idsToFetch.length === 0) {
2567
+ return;
2568
+ }
2569
+ const previewResponse = await apiClient.getStylesByIds(idsToFetch, "preview");
2570
+ const frontendResponse = await apiClient.getStylesByIds(idsToFetch, "frontend");
2571
+ const previewItems = styleDefinitionsMapWithoutNull(previewResponse.data.data);
2572
+ const frontendItems = styleDefinitionsMapWithoutNull(frontendResponse.data.data);
2573
+ dispatch5(slice.actions.mergeExistingClasses({ preview: previewItems, frontend: frontendItems }));
2574
+ }
2575
+
2576
+ // src/global-classes-styles-provider.ts
2577
+ var MAX_CLASSES = 5e3;
2578
+ var GLOBAL_CLASSES_PROVIDER_KEY = "global-classes";
2579
+ var PREGENERATED_LINK_PATTERN = /^global-([0-9]+-)?(preview|frontend)-[a-zA-Z_-]+-css$/;
2580
+ var globalClassesStylesProvider = createStylesProvider({
2581
+ key: GLOBAL_CLASSES_PROVIDER_KEY,
2582
+ priority: 30,
2583
+ limit: MAX_CLASSES,
2584
+ isPregeneratedLink: ({ id: id2 }) => PREGENERATED_LINK_PATTERN.test(id2),
2585
+ labels: {
2586
+ singular: __15("class", "elementor"),
2587
+ plural: __15("classes", "elementor")
2588
+ },
2589
+ subscribe: (cb) => subscribeWithStates(cb),
2590
+ capabilities: getCapabilities(),
2591
+ actions: {
2592
+ all: () => selectOrderedClasses(getState4()),
2593
+ get: (id2) => {
2594
+ const state = getState4();
2595
+ const isFetched = selectIsClassFetched(state, id2);
2596
+ const style = selectClass(state, id2);
2597
+ if (isFetched || style) {
2598
+ return style;
2599
+ }
2600
+ loadExistingClasses([id2]);
2601
+ const label = selectClassLabels(state)[id2] ?? id2;
2602
+ return placeholderDefinition(id2, label);
2603
+ },
2604
+ resolveCssName: (id2) => {
2605
+ const state = getState4();
2606
+ const loaded = selectClass(state, id2);
2607
+ if (loaded) {
2608
+ return loaded.label;
2609
+ }
2610
+ const fromIndex = selectClassLabels(state)[id2];
2611
+ return fromIndex ?? id2;
2612
+ },
2613
+ create: (label, variants = [], id2) => {
2614
+ const existingClasses = Object.entries(selectClassLabels(getState4()));
2615
+ const existingLabels = existingClasses.map(([, classLabel]) => classLabel);
2616
+ if (existingLabels.includes(label)) {
2617
+ throw new GlobalClassLabelAlreadyExistsError({ context: { label } });
2618
+ }
2619
+ const existingIds = existingClasses.map(([existingId]) => existingId);
2620
+ if (!id2) {
2621
+ id2 = generateId("g-", existingIds);
2622
+ }
2623
+ dispatch6(
2624
+ slice.actions.add({
2625
+ id: id2,
2626
+ type: "class",
2627
+ label,
2628
+ variants
2629
+ })
2630
+ );
2631
+ return id2;
2632
+ },
2633
+ update: (payload) => {
2634
+ dispatch6(
2635
+ slice.actions.update({
2636
+ style: payload
2637
+ })
2638
+ );
2639
+ },
2640
+ delete: (id2) => {
2641
+ dispatch6(slice.actions.delete(id2));
2642
+ },
2643
+ updateProps: (args) => {
2644
+ dispatch6(
2645
+ slice.actions.updateProps({
2646
+ id: args.id,
2647
+ meta: args.meta,
2648
+ props: args.props,
2649
+ mode: args.mode
2650
+ })
2651
+ );
2652
+ },
2653
+ updateCustomCss: (args) => {
2654
+ dispatch6(
2655
+ slice.actions.updateProps({
2656
+ id: args.id,
2657
+ meta: args.meta,
2658
+ custom_css: args.custom_css,
2659
+ props: {}
2660
+ })
2661
+ );
2662
+ },
2663
+ tracking: (data) => {
2664
+ trackGlobalClasses(data).catch((error) => {
2665
+ throw new GlobalClassTrackingError({ cause: error });
2666
+ });
2667
+ }
2668
+ }
2669
+ });
2670
+ var subscribeWithStates = (cb) => {
2671
+ let previousState = selectData(getState4());
2672
+ return subscribeWithSelector(
2673
+ (state) => selectData(state),
2674
+ (currentState) => {
2675
+ cb(previousState.items, currentState.items);
2676
+ previousState = currentState;
2677
+ }
2678
+ );
2679
+ };
2680
+
2681
+ // src/mcp-integration/classes-resource.ts
2682
+ var GLOBAL_CLASSES_URI = "elementor://global-classes";
2683
+ var STORAGE_KEY = "elementor-global-classes";
2684
+ var updateLocalStorageCache = () => {
2685
+ const classes = selectOrderedClasses(getState5());
2686
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(classes));
2687
+ };
2688
+ var initClassesResource = (classesMcpEntry, canvasMcpEntry) => {
2689
+ [canvasMcpEntry, classesMcpEntry].forEach((entry) => {
2690
+ const { sendResourceUpdated, resource, waitForReady } = entry;
2691
+ resource(
2692
+ "global-classes",
2693
+ GLOBAL_CLASSES_URI,
2694
+ {
2695
+ description: "Global classes list."
2696
+ },
2697
+ async () => {
2698
+ return {
2699
+ contents: [{ uri: GLOBAL_CLASSES_URI, text: localStorage[STORAGE_KEY] ?? "[]" }]
2700
+ };
2701
+ }
2702
+ );
2703
+ waitForReady().then(() => {
2704
+ updateLocalStorageCache();
2705
+ globalClassesStylesProvider.subscribe(() => {
2706
+ updateLocalStorageCache();
2707
+ sendResourceUpdated({ uri: GLOBAL_CLASSES_URI });
2708
+ });
2709
+ });
2710
+ });
2711
+ };
2712
+
2713
+ // src/init.ts
2714
+ import { injectIntoLogic } from "@elementor/editor";
2715
+ import {
2716
+ injectIntoClassSelectorActions,
2717
+ injectIntoCssClassConvert,
2718
+ registerStyleProviderToColors
2719
+ } from "@elementor/editor-editing-panel";
2720
+ import { getMCPByDomain } from "@elementor/editor-mcp";
2721
+ import { __registerPanel as registerPanel } from "@elementor/editor-panels";
2722
+ import { stylesRepository } from "@elementor/editor-styles-repository";
2723
+ import { isExperimentActive as isExperimentActive4 } from "@elementor/editor-v1-adapters";
2724
+ import { __registerSlice as registerSlice } from "@elementor/store";
2725
+
2726
+ // src/components/class-manager/class-manager-button.tsx
2727
+ import * as React20 from "react";
2728
+ import {
2729
+ __useActiveDocument as useActiveDocument2,
2730
+ __useActiveDocumentActions as useActiveDocumentActions
2731
+ } from "@elementor/editor-documents";
2732
+ import { useUserStylesCapability } from "@elementor/editor-styles-repository";
2733
+ import { SaveChangesDialog as SaveChangesDialog2, useDialog as useDialog2 } from "@elementor/editor-ui";
2734
+ import { isExperimentActive as isExperimentActive2 } from "@elementor/editor-v1-adapters";
2735
+ import { IconButton as IconButton5, Tooltip as Tooltip6 } from "@elementor/ui";
2736
+ import { __ as __16 } from "@wordpress/i18n";
2737
+
2738
+ // src/hooks/use-prefetch-css-class-usage.ts
2739
+ import { useQueryClient } from "@elementor/query";
2740
+ function usePrefetchCssClassUsage() {
2741
+ const queryClient = useQueryClient();
2742
+ const prefetchClassesUsage = () => queryClient.prefetchQuery({
2743
+ queryKey: [QUERY_KEY],
2744
+ queryFn: fetchCssClassUsage
2745
+ });
2746
+ return { prefetchClassesUsage };
2747
+ }
2748
+ var PrefetchCssClassUsage = () => {
2749
+ const { prefetchClassesUsage } = usePrefetchCssClassUsage();
2750
+ prefetchClassesUsage();
2751
+ return null;
2752
+ };
2753
+
2428
2754
  // src/components/class-manager/class-manager-button.tsx
2429
2755
  var trackGlobalClassesButton = () => {
2430
2756
  trackGlobalClasses({
@@ -2443,17 +2769,24 @@ var ClassManagerButton = () => {
2443
2769
  if (!isUserAllowedToUpdateClass) {
2444
2770
  return null;
2445
2771
  }
2772
+ const toggleClassesManagerPanel = () => {
2773
+ if (isExperimentActive2("e_editor_design_system_panel")) {
2774
+ window.dispatchEvent(
2775
+ new CustomEvent("elementor/toggle-design-system", {
2776
+ detail: { tab: "classes" }
2777
+ })
2778
+ );
2779
+ } else {
2780
+ openPanel();
2781
+ }
2782
+ };
2446
2783
  const handleOpenPanel = () => {
2447
2784
  if (document?.isDirty) {
2448
2785
  openSaveChangesDialog();
2449
2786
  return;
2450
2787
  }
2451
- openPanel();
2788
+ toggleClassesManagerPanel();
2452
2789
  trackGlobalClassesButton();
2453
- trackGlobalClasses({
2454
- event: "classManagerOpened",
2455
- source: "style-panel"
2456
- });
2457
2790
  prefetchClassesUsage();
2458
2791
  };
2459
2792
  return /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement(Tooltip6, { title: __16("Class Manager", "elementor"), placement: "top" }, /* @__PURE__ */ React20.createElement(IconButton5, { size: "tiny", onClick: handleOpenPanel, sx: { marginInlineEnd: -0.75 } }, /* @__PURE__ */ React20.createElement(FlippedColorSwatchIcon, { fontSize: "tiny" }))), isSaveChangesDialogOpen && /* @__PURE__ */ React20.createElement(SaveChangesDialog2, null, /* @__PURE__ */ React20.createElement(SaveChangesDialog2.Title, null, __16("You have unsaved changes", "elementor")), /* @__PURE__ */ React20.createElement(SaveChangesDialog2.Content, null, /* @__PURE__ */ React20.createElement(SaveChangesDialog2.ContentText, { sx: { mb: 2 } }, __16(
@@ -2472,7 +2805,7 @@ var ClassManagerButton = () => {
2472
2805
  action: async () => {
2473
2806
  await saveDocument();
2474
2807
  closeSaveChangesDialog();
2475
- openPanel();
2808
+ toggleClassesManagerPanel();
2476
2809
  trackGlobalClassesButton();
2477
2810
  prefetchClassesUsage();
2478
2811
  }
@@ -2534,52 +2867,28 @@ function createClassName(prefix) {
2534
2867
 
2535
2868
  // src/components/global-styles-import-listener.tsx
2536
2869
  import { useEffect as useEffect5 } from "react";
2870
+ import { GLOBAL_STYLES_IMPORTED_EVENT } from "@elementor/editor-canvas";
2537
2871
  import { __useDispatch as useDispatch2 } from "@elementor/store";
2538
2872
  function GlobalStylesImportListener() {
2539
- const dispatch5 = useDispatch2();
2873
+ const dispatch7 = useDispatch2();
2540
2874
  useEffect5(() => {
2541
2875
  const handleGlobalStylesImported = (event) => {
2542
2876
  const importedClasses = event.detail?.global_classes;
2543
2877
  if (importedClasses?.items && importedClasses?.order) {
2544
- dispatch5(
2545
- slice.actions.load({
2546
- preview: {
2547
- items: importedClasses.items,
2548
- order: importedClasses.order
2549
- },
2550
- frontend: {
2551
- items: importedClasses.items,
2552
- order: importedClasses.order
2553
- }
2878
+ const { items } = importedClasses;
2879
+ dispatch7(
2880
+ slice.actions.mergeExistingClasses({
2881
+ preview: items,
2882
+ frontend: items
2554
2883
  })
2555
2884
  );
2556
2885
  }
2557
- Promise.all([apiClient.all("preview"), apiClient.all("frontend")]).then(([previewRes, frontendRes]) => {
2558
- const { data: previewData } = previewRes;
2559
- const { data: frontendData } = frontendRes;
2560
- dispatch5(
2561
- slice.actions.load({
2562
- preview: {
2563
- items: previewData.data,
2564
- order: previewData.meta.order
2565
- },
2566
- frontend: {
2567
- items: frontendData.data,
2568
- order: frontendData.meta.order
2569
- }
2570
- })
2571
- );
2572
- }).catch(() => {
2573
- });
2574
2886
  };
2575
- window.addEventListener("elementor/global-styles/imported", handleGlobalStylesImported);
2887
+ window.addEventListener(GLOBAL_STYLES_IMPORTED_EVENT, handleGlobalStylesImported);
2576
2888
  return () => {
2577
- window.removeEventListener(
2578
- "elementor/global-styles/imported",
2579
- handleGlobalStylesImported
2580
- );
2889
+ window.removeEventListener(GLOBAL_STYLES_IMPORTED_EVENT, handleGlobalStylesImported);
2581
2890
  };
2582
- }, [dispatch5]);
2891
+ }, [dispatch7]);
2583
2892
  return null;
2584
2893
  }
2585
2894
 
@@ -2614,29 +2923,14 @@ function OpenPanelFromUrl() {
2614
2923
 
2615
2924
  // src/components/populate-store.tsx
2616
2925
  import { useEffect as useEffect7 } from "react";
2617
- import { __useDispatch as useDispatch3 } from "@elementor/store";
2926
+ import { registerDataHook } from "@elementor/editor-v1-adapters";
2618
2927
  function PopulateStore() {
2619
- const dispatch5 = useDispatch3();
2620
2928
  useEffect7(() => {
2621
- Promise.all([apiClient.all("preview"), apiClient.all("frontend")]).then(
2622
- ([previewRes, frontendRes]) => {
2623
- const { data: previewData } = previewRes;
2624
- const { data: frontendData } = frontendRes;
2625
- dispatch5(
2626
- slice.actions.load({
2627
- preview: {
2628
- items: previewData.data,
2629
- order: previewData.meta.order
2630
- },
2631
- frontend: {
2632
- items: frontendData.data,
2633
- order: frontendData.meta.order
2634
- }
2635
- })
2636
- );
2637
- }
2638
- );
2639
- }, [dispatch5]);
2929
+ loadCurrentDocumentClasses();
2930
+ registerDataHook("after", "editor/documents/attach-preview", async () => {
2931
+ await loadCurrentDocumentClasses();
2932
+ });
2933
+ }, []);
2640
2934
  return null;
2641
2935
  }
2642
2936
 
@@ -2716,7 +3010,7 @@ function initMcpApplyUnapplyGlobalClasses(server) {
2716
3010
  - Make sure you have the correct class ID that you want to unapply.
2717
3011
 
2718
3012
  <note>
2719
- If the user want to unapply a class by it's name and not ID, retreive the id from the list, available at uri elementor://global-classes
3013
+ If the user want to unapply a class by it's name and not ID, retrieve the id from the list, available at uri elementor://global-classes
2720
3014
  </note>
2721
3015
  `,
2722
3016
  handler: async (params) => {
@@ -2740,7 +3034,7 @@ function initMcpApplyGetGlobalClassUsages(reg) {
2740
3034
  usages: z2.array(
2741
3035
  z2.object({
2742
3036
  classId: z2.string().describe(
2743
- 'The ID of the class, not visible to the user. To retreive the name of the class, use the "list-global-classes" tool'
3037
+ 'The ID of the class, not visible to the user. To retrieve the name of the class, use the "list-global-classes" tool'
2744
3038
  ),
2745
3039
  usages: z2.array(
2746
3040
  z2.object({
@@ -2759,13 +3053,13 @@ function initMcpApplyGetGlobalClassUsages(reg) {
2759
3053
  intelligencePriority: 0.6,
2760
3054
  speedPriority: 0.8
2761
3055
  },
2762
- description: `Retreive the usages of global-classes ACCROSS PAGES designed by Elementor editor.
3056
+ description: `Retrieve the usages of global-classes ACROSS PAGES designed by Elementor editor.
2763
3057
 
2764
- ## Prequisites: CRITICAL
3058
+ ## Prerequisites: CRITICAL
2765
3059
  - The list of global classes and their applid values is available at resource uri elementor://global-classes
2766
3060
 
2767
3061
  ## When to use this tool:
2768
- - When a user requests to see where a specific global class is being used accross the site.
3062
+ - When a user requests to see where a specific global class is being used across the site.
2769
3063
  - When you need to manage or clean up unused global classes.
2770
3064
  - Before deleting a global class, to ensure it is not in use in any other pages.
2771
3065
 
@@ -3005,7 +3299,7 @@ async function attemptCreate(opts) {
3005
3299
  }
3006
3300
  ]);
3007
3301
  try {
3008
- await saveGlobalClasses({ context: "frontend" });
3302
+ await saveGlobalClasses2({ context: "frontend" });
3009
3303
  return newClassId;
3010
3304
  } catch {
3011
3305
  deleteClass2(newClassId);
@@ -3031,7 +3325,7 @@ async function attemptUpdate(opts) {
3031
3325
  state
3032
3326
  }
3033
3327
  });
3034
- await saveGlobalClasses({ context: "frontend" });
3328
+ await saveGlobalClasses2({ context: "frontend" });
3035
3329
  return true;
3036
3330
  } catch {
3037
3331
  snapshot.forEach((style) => {
@@ -3040,7 +3334,7 @@ async function attemptUpdate(opts) {
3040
3334
  variants: style.variants
3041
3335
  });
3042
3336
  });
3043
- await saveGlobalClasses({ context: "frontend" });
3337
+ await saveGlobalClasses2({ context: "frontend" });
3044
3338
  return false;
3045
3339
  }
3046
3340
  }
@@ -3060,7 +3354,7 @@ async function attemptDelete(opts) {
3060
3354
  }
3061
3355
  try {
3062
3356
  deleteClass2(classId);
3063
- await saveGlobalClasses({ context: "frontend" });
3357
+ await saveGlobalClasses2({ context: "frontend" });
3064
3358
  return true;
3065
3359
  } catch {
3066
3360
  return false;
@@ -3087,13 +3381,13 @@ var initMcpIntegration = (reg, canvasMcpEntry) => {
3087
3381
 
3088
3382
  // src/sync-with-document.tsx
3089
3383
  import { useEffect as useEffect8 } from "react";
3090
- import { __privateListenTo as listenTo2, v1ReadyEvent } from "@elementor/editor-v1-adapters";
3384
+ import { __privateListenTo as listenTo2, isExperimentActive as isExperimentActive3, v1ReadyEvent } from "@elementor/editor-v1-adapters";
3091
3385
 
3092
3386
  // src/sync-with-document-save.ts
3093
3387
  import { getCurrentUser } from "@elementor/editor-current-user";
3094
3388
  import { setDocumentModifiedStatus as setDocumentModifiedStatus2 } from "@elementor/editor-documents";
3095
- import { registerDataHook } from "@elementor/editor-v1-adapters";
3096
- import { __getState as getState4, __subscribeWithSelector as subscribeWithSelector2 } from "@elementor/store";
3389
+ import { registerDataHook as registerDataHook2 } from "@elementor/editor-v1-adapters";
3390
+ import { __getState as getState6, __subscribeWithSelector as subscribeWithSelector2 } from "@elementor/store";
3097
3391
  var pendingSave = null;
3098
3392
  function syncWithDocumentSave(panelActions) {
3099
3393
  const unsubscribe = syncDirtyState();
@@ -3118,7 +3412,7 @@ function triggerSave(panelActions, context2 = "preview") {
3118
3412
  if (pendingSave) {
3119
3413
  return pendingSave;
3120
3414
  }
3121
- const promise = saveGlobalClasses({
3415
+ const promise = saveGlobalClasses2({
3122
3416
  context: context2,
3123
3417
  onApprove: panelActions?.open
3124
3418
  });
@@ -3129,7 +3423,7 @@ function triggerSave(panelActions, context2 = "preview") {
3129
3423
  return promise;
3130
3424
  }
3131
3425
  function bindSaveAction(panelActions) {
3132
- registerDataHook("dependency", "document/save/save", (args) => {
3426
+ registerDataHook2("dependency", "document/save/save", (args) => {
3133
3427
  triggerSave(panelActions, args.status === "publish" ? "frontend" : "preview");
3134
3428
  return true;
3135
3429
  });
@@ -3145,16 +3439,20 @@ function bindBeforeSaveTemplateAction() {
3145
3439
  }));
3146
3440
  }
3147
3441
  function isDirty() {
3148
- return selectIsDirty(getState4());
3442
+ return selectIsDirty(getState6());
3149
3443
  }
3150
3444
 
3151
3445
  // src/sync-with-document.tsx
3152
3446
  function SyncWithDocumentSave() {
3153
- const panelActions = usePanelActions();
3447
+ const { open: openClassPanel } = usePanelActions();
3154
3448
  useEffect8(() => {
3155
- listenTo2(v1ReadyEvent(), () => {
3156
- syncWithDocumentSave(panelActions);
3449
+ const unsubscribe = listenTo2(v1ReadyEvent(), () => {
3450
+ const open = isExperimentActive3("e_editor_design_system_panel") ? () => {
3451
+ window.dispatchEvent(new CustomEvent("elementor/open-global-classes-manager"));
3452
+ } : openClassPanel;
3453
+ syncWithDocumentSave({ open });
3157
3454
  });
3455
+ return unsubscribe;
3158
3456
  }, []);
3159
3457
  return null;
3160
3458
  }
@@ -3162,7 +3460,9 @@ function SyncWithDocumentSave() {
3162
3460
  // src/init.ts
3163
3461
  function init() {
3164
3462
  registerSlice(slice);
3165
- registerPanel(panel);
3463
+ if (!isExperimentActive4("e_editor_design_system_panel")) {
3464
+ registerPanel(panel);
3465
+ }
3166
3466
  stylesRepository.register(globalClassesStylesProvider);
3167
3467
  injectIntoLogic({
3168
3468
  id: "global-classes-populate-store",
@@ -3180,10 +3480,12 @@ function init() {
3180
3480
  id: "global-classes-prefetch-css-class-usage",
3181
3481
  component: PrefetchCssClassUsage
3182
3482
  });
3183
- injectIntoLogic({
3184
- id: "global-classes-open-panel-from-url",
3185
- component: OpenPanelFromUrl
3186
- });
3483
+ if (!isExperimentActive4("e_editor_design_system_panel")) {
3484
+ injectIntoLogic({
3485
+ id: "global-classes-open-panel-from-url",
3486
+ component: OpenPanelFromUrl
3487
+ });
3488
+ }
3187
3489
  injectIntoCssClassConvert({
3188
3490
  id: "global-classes-convert-from-local-class",
3189
3491
  component: ConvertLocalClassToGlobalClass
@@ -3202,7 +3504,11 @@ function init() {
3202
3504
  );
3203
3505
  }
3204
3506
  export {
3507
+ ClassManagerPanelEmbedded,
3205
3508
  GLOBAL_CLASSES_URI,
3206
- init
3509
+ addDocumentClasses,
3510
+ createLabelsForClasses,
3511
+ init,
3512
+ loadExistingClasses
3207
3513
  };
3208
3514
  //# sourceMappingURL=index.mjs.map