@elementor/editor-global-classes 4.2.0-888 → 4.2.0-894

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
@@ -2146,10 +2146,25 @@ var StartSyncToV3Modal = ({
2146
2146
 
2147
2147
  // src/components/class-manager/class-manager-panel.tsx
2148
2148
  var STOP_SYNC_MESSAGE_KEY = "stop-sync-class";
2149
- function ClassManagerPanelEmbedded({ onRequestClose, onExposeCloseAttempt }) {
2150
- return /* @__PURE__ */ React19.createElement(ClassManagerPanelContent, { onRequestClose, onExposeCloseAttempt });
2149
+ function ClassManagerPanelEmbedded({
2150
+ onRequestClose,
2151
+ onExposeCloseAttempt,
2152
+ isActive
2153
+ }) {
2154
+ return /* @__PURE__ */ React19.createElement(
2155
+ ClassManagerPanelContent,
2156
+ {
2157
+ onRequestClose,
2158
+ onExposeCloseAttempt,
2159
+ isActive
2160
+ }
2161
+ );
2151
2162
  }
2152
- function ClassManagerPanelContent({ onRequestClose, onExposeCloseAttempt }) {
2163
+ function ClassManagerPanelContent({
2164
+ onRequestClose,
2165
+ onExposeCloseAttempt,
2166
+ isActive = true
2167
+ }) {
2153
2168
  const isDirty2 = useDirtyState();
2154
2169
  const { open: openSaveChangesDialog, close: closeSaveChangesDialog, isOpen: isSaveChangesDialogOpen } = useDialog();
2155
2170
  const [stopSyncConfirmation, setStopSyncConfirmation] = useState7(null);
@@ -2276,7 +2291,7 @@ function ClassManagerPanelContent({ onRequestClose, onExposeCloseAttempt }) {
2276
2291
  },
2277
2292
  __14("Save changes", "elementor")
2278
2293
  ))
2279
- ))), /* @__PURE__ */ React19.createElement(ClassManagerIntroduction, null), startSyncConfirmation && /* @__PURE__ */ React19.createElement(
2294
+ ))), isActive && /* @__PURE__ */ React19.createElement(ClassManagerIntroduction, null), startSyncConfirmation && /* @__PURE__ */ React19.createElement(
2280
2295
  StartSyncToV3Modal,
2281
2296
  {
2282
2297
  externalOpen: true,
@@ -2495,8 +2510,10 @@ async function fetchAndMergeClasses() {
2495
2510
  if (idsToFetch.length === 0) {
2496
2511
  return;
2497
2512
  }
2498
- const previewResponse = await apiClient.getStylesByIds(idsToFetch, "preview");
2499
- const frontendResponse = await apiClient.getStylesByIds(idsToFetch, "frontend");
2513
+ const [previewResponse, frontendResponse] = await Promise.all([
2514
+ apiClient.getStylesByIds(idsToFetch, "preview"),
2515
+ apiClient.getStylesByIds(idsToFetch, "frontend")
2516
+ ]);
2500
2517
  const previewItems = styleDefinitionsMapWithoutNull(previewResponse.data.data);
2501
2518
  const frontendItems = styleDefinitionsMapWithoutNull(frontendResponse.data.data);
2502
2519
  dispatch5(slice.actions.mergeExistingClasses({ preview: previewItems, frontend: frontendItems }));
@@ -2652,12 +2669,7 @@ import { __registerSlice as registerSlice } from "@elementor/store";
2652
2669
 
2653
2670
  // src/components/class-manager/class-manager-button.tsx
2654
2671
  import * as React20 from "react";
2655
- import {
2656
- __useActiveDocument as useActiveDocument2,
2657
- __useActiveDocumentActions as useActiveDocumentActions
2658
- } from "@elementor/editor-documents";
2659
2672
  import { useUserStylesCapability } from "@elementor/editor-styles-repository";
2660
- import { SaveChangesDialog as SaveChangesDialog2, useDialog as useDialog2 } from "@elementor/editor-ui";
2661
2673
  import { IconButton as IconButton4, Tooltip as Tooltip6 } from "@elementor/ui";
2662
2674
  import { __ as __16 } from "@wordpress/i18n";
2663
2675
 
@@ -2678,62 +2690,27 @@ var PrefetchCssClassUsage = () => {
2678
2690
  };
2679
2691
 
2680
2692
  // src/components/class-manager/class-manager-button.tsx
2681
- var trackGlobalClassesButton = () => {
2682
- trackGlobalClasses({
2683
- event: "classManagerOpened",
2684
- source: "style-panel"
2685
- });
2686
- };
2693
+ var EVENT_TOGGLE_DESIGN_SYSTEM = "elementor/toggle-design-system";
2687
2694
  var ClassManagerButton = () => {
2688
- const document = useActiveDocument2();
2689
- const { save: saveDocument } = useActiveDocumentActions();
2690
- const { open: openSaveChangesDialog, close: closeSaveChangesDialog, isOpen: isSaveChangesDialogOpen } = useDialog2();
2691
2695
  const { prefetchClassesUsage } = usePrefetchCssClassUsage();
2692
2696
  const { userCan } = useUserStylesCapability();
2693
2697
  const isUserAllowedToUpdateClass = userCan(globalClassesStylesProvider.getKey()).update;
2694
2698
  if (!isUserAllowedToUpdateClass) {
2695
2699
  return null;
2696
2700
  }
2697
- const toggleClassesManagerPanel = () => {
2701
+ const handleOpenPanel = () => {
2698
2702
  window.dispatchEvent(
2699
- new CustomEvent("elementor/toggle-design-system", {
2703
+ new CustomEvent(EVENT_TOGGLE_DESIGN_SYSTEM, {
2700
2704
  detail: { tab: "classes" }
2701
2705
  })
2702
2706
  );
2703
- };
2704
- const handleOpenPanel = () => {
2705
- if (document?.isDirty) {
2706
- openSaveChangesDialog();
2707
- return;
2708
- }
2709
- toggleClassesManagerPanel();
2710
- trackGlobalClassesButton();
2707
+ trackGlobalClasses({
2708
+ event: "classManagerOpened",
2709
+ source: "style-panel"
2710
+ });
2711
2711
  prefetchClassesUsage();
2712
2712
  };
2713
- return /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement(Tooltip6, { title: __16("Class Manager", "elementor"), placement: "top" }, /* @__PURE__ */ React20.createElement(IconButton4, { 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(
2714
- "To open the Class Manager, save your page first. You can't continue without saving.",
2715
- "elementor"
2716
- ))), /* @__PURE__ */ React20.createElement(
2717
- SaveChangesDialog2.Actions,
2718
- {
2719
- actions: {
2720
- cancel: {
2721
- label: __16("Stay here", "elementor"),
2722
- action: closeSaveChangesDialog
2723
- },
2724
- confirm: {
2725
- label: __16("Save & Continue", "elementor"),
2726
- action: async () => {
2727
- await saveDocument();
2728
- closeSaveChangesDialog();
2729
- toggleClassesManagerPanel();
2730
- trackGlobalClassesButton();
2731
- prefetchClassesUsage();
2732
- }
2733
- }
2734
- }
2735
- }
2736
- )));
2713
+ return /* @__PURE__ */ React20.createElement(Tooltip6, { title: __16("Class Manager", "elementor"), placement: "top" }, /* @__PURE__ */ React20.createElement(IconButton4, { size: "tiny", onClick: handleOpenPanel, sx: { marginInlineEnd: -0.75 } }, /* @__PURE__ */ React20.createElement(FlippedColorSwatchIcon, { fontSize: "tiny" })));
2737
2714
  };
2738
2715
 
2739
2716
  // src/components/convert-local-class-to-global-class.tsx
@@ -2996,7 +2973,7 @@ function initMcpApplyGetGlobalClassUsages(reg) {
2996
2973
  }
2997
2974
 
2998
2975
  // src/mcp-integration/mcp-manage-global-classes.ts
2999
- import { BREAKPOINTS_SCHEMA_URI, STYLE_SCHEMA_URI } from "@elementor/editor-canvas";
2976
+ import { BREAKPOINTS_SCHEMA_FULL_URI, STYLE_SCHEMA_FULL_URI } from "@elementor/editor-canvas";
3000
2977
  import { Schema } from "@elementor/editor-props";
3001
2978
  import { getStylesSchema } from "@elementor/editor-styles";
3002
2979
  import { z as z3 } from "@elementor/schema";
@@ -3005,12 +2982,30 @@ var schema = {
3005
2982
  classId: z3.string().optional().describe("Global class ID (required for modify). Get from elementor://global-classes resource."),
3006
2983
  globalClassName: z3.string().optional().describe("Global class name (required for create)"),
3007
2984
  props: z3.object({
3008
- default: z3.record(z3.any()).describe(
3009
- 'key-value of style-schema PropValues. Available properties at dynamic resource "elementor://styles/schema/{property-name}"'
2985
+ default: z3.record(
2986
+ z3.string().describe("The style property name"),
2987
+ z3.any().describe(`The style PropValue, refer to [${STYLE_SCHEMA_FULL_URI}] how to generate values`)
2988
+ ).describe(
2989
+ "An object record containing style property names and their new values. MUST contain at least one property \u2014 empty objects are rejected."
3010
2990
  ),
3011
- hover: z3.record(z3.any()).describe("key-value of style-schema PropValues, for :hover css state. optional").optional(),
3012
- focus: z3.record(z3.any()).describe("key-value of style-schema PropValues, for :focus css state. optional").optional(),
3013
- active: z3.record(z3.any()).describe("key-value of style-schema PropValues, for :active css state. optional").optional()
2991
+ hover: z3.record(
2992
+ z3.string().describe("The style property name"),
2993
+ z3.any().describe(`The style PropValue, refer to [${STYLE_SCHEMA_FULL_URI}] how to generate values`)
2994
+ ).describe(
2995
+ "An object record containing style property names and their new values to be set on the element. for :hover css state. optional"
2996
+ ).optional(),
2997
+ focus: z3.record(
2998
+ z3.string().describe("The style property name"),
2999
+ z3.any().describe(`The style PropValue, refer to [${STYLE_SCHEMA_FULL_URI}] how to generate values`)
3000
+ ).describe(
3001
+ "An object record containing style property names and their new values to be set on the element. for :focus css state. optional"
3002
+ ).optional(),
3003
+ active: z3.record(
3004
+ z3.string().describe("The style property name"),
3005
+ z3.any().describe(`The style PropValue, refer to [${STYLE_SCHEMA_FULL_URI}] how to generate values`)
3006
+ ).describe(
3007
+ "An object record containing style property names and their new values to be set on the element. for :active css state. optional"
3008
+ ).optional()
3014
3009
  }),
3015
3010
  breakpoint: z3.nullable(z3.string().describe("Responsive breakpoint name for styles. Defaults to desktop (null).")).default(null).describe("Responsive breakpoint name for styles. Defaults to desktop (null).")
3016
3011
  };
@@ -3066,16 +3061,32 @@ var handler = async (input) => {
3066
3061
  }
3067
3062
  });
3068
3063
  });
3064
+ if (action !== "delete") {
3065
+ const hasAnyProps = Object.values(propsWithStates).some(
3066
+ (stateProps) => Object.keys(stateProps).length > 0
3067
+ );
3068
+ if (!hasAnyProps) {
3069
+ throw new Error(
3070
+ `Props must not be empty. Each prop must be a PropValue object from the style schema.
3071
+
3072
+ Example: { "display": { "$$type": "string", "value": "flex" }, "flex-direction": { "$$type": "string", "value": "column" } }
3073
+
3074
+ ${STYLE_SCHEMA_FULL_URI} to get the allowed values (look at the "value" enum in the schema response), then construct { "$$type": "string", "value": "<chosen value>" } for each property.
3075
+ Available Properties: ${validProps.join(
3076
+ ", "
3077
+ )}`
3078
+ );
3079
+ }
3080
+ }
3069
3081
  if (errors.length > 0) {
3070
- return {
3071
- status: "error",
3072
- message: `Validation errors:
3082
+ throw new Error(
3083
+ `Validation errors:
3073
3084
  ${errors.join("\n")}
3074
3085
  Available Properties: ${validProps.join(
3075
3086
  ", "
3076
3087
  )}
3077
3088
  Update your input and try again.`
3078
- };
3089
+ );
3079
3090
  }
3080
3091
  const Utils = window.elementorV2.editorVariables.Utils;
3081
3092
  Object.values(propsWithStates).forEach((props) => {
@@ -3092,6 +3103,16 @@ Update your input and try again.`
3092
3103
  message: "unknown error"
3093
3104
  };
3094
3105
  try {
3106
+ if (action === "delete") {
3107
+ const deleted = await attemptDelete({
3108
+ classId,
3109
+ stylesProvider: globalClassesStylesProvider
3110
+ });
3111
+ if (deleted) {
3112
+ return { status: "ok", message: `deleted global class with ID ${classId}` };
3113
+ }
3114
+ throw new Error("error deleting class");
3115
+ }
3095
3116
  let currentAction = action;
3096
3117
  for await (const [state, props] of Object.entries(propsWithStates)) {
3097
3118
  switch (currentAction) {
@@ -3106,14 +3127,13 @@ Update your input and try again.`
3106
3127
  if (newClassId && currentAction === "create") {
3107
3128
  currentAction = "modify";
3108
3129
  classId = newClassId;
3130
+ result = {
3131
+ status: "ok",
3132
+ message: `created global class with ID ${newClassId}`
3133
+ };
3134
+ } else {
3135
+ throw new Error("error creating class");
3109
3136
  }
3110
- result = newClassId ? {
3111
- status: "ok",
3112
- message: `created global class with ID ${newClassId}`
3113
- } : {
3114
- status: "error",
3115
- message: "error creating class"
3116
- };
3117
3137
  break;
3118
3138
  case "modify":
3119
3139
  const updated = await attemptUpdate({
@@ -3123,20 +3143,11 @@ Update your input and try again.`
3123
3143
  breakpoint: breakpointValue,
3124
3144
  state
3125
3145
  });
3126
- result = updated ? { status: "ok", classId } : {
3127
- status: "error",
3128
- message: "error modifying class"
3129
- };
3130
- break;
3131
- case "delete":
3132
- const deleted = await attemptDelete({
3133
- classId,
3134
- stylesProvider: globalClassesStylesProvider
3135
- });
3136
- result = deleted ? { status: "ok", message: `deleted global class with ID ${classId}` } : {
3137
- status: "error",
3138
- message: "error deleting class"
3139
- };
3146
+ if (updated) {
3147
+ result = { status: "ok", classId };
3148
+ } else {
3149
+ throw new Error("error modifying class");
3150
+ }
3140
3151
  break;
3141
3152
  default:
3142
3153
  throw new Error(`Unsupported action ${action}`);
@@ -3156,10 +3167,21 @@ var initManageGlobalClasses = (reg) => {
3156
3167
  name: "manage-global-classes",
3157
3168
  requiredResources: [
3158
3169
  { uri: GLOBAL_CLASSES_URI, description: "Global classes list" },
3159
- { uri: STYLE_SCHEMA_URI, description: "Style schema resources" },
3160
- { uri: BREAKPOINTS_SCHEMA_URI, description: "Breakpoints list" }
3170
+ { uri: STYLE_SCHEMA_FULL_URI, description: "Style schema resources" },
3171
+ { uri: BREAKPOINTS_SCHEMA_FULL_URI, description: "Breakpoints list" }
3161
3172
  ],
3162
- description: `Create or modify global classes for reusable design-system styling. Class names must reflect purpose (e.g. heading-primary, button-cta). Create classes BEFORE compositions. Do NOT create classes for one-off styles or layout-specific properties.`,
3173
+ description: `Create or modify global classes for reusable design-system styling. Class names must reflect purpose (e.g. heading-primary, button-cta). Create classes BEFORE applying them. Do NOT create classes for one-off styles.
3174
+
3175
+ IMPORTANT: props must contain actual CSS property values \u2014 never pass empty objects.
3176
+ Fetch ${STYLE_SCHEMA_FULL_URI} to get the allowed values for each property, then use them to build the props object.
3177
+
3178
+ Example \u2014 creating a flex column class:
3179
+ props.default = {
3180
+ "display": { "$$type": "string", "value": "flex" },
3181
+ "flex-direction": { "$$type": "string", "value": "column" }
3182
+ }
3183
+
3184
+ The style schema returns a JSON Schema. Extract the "value" enum to pick the right value, then construct { "$$type": "string", "value": "<picked value>" }.`,
3163
3185
  schema,
3164
3186
  outputSchema,
3165
3187
  handler
@@ -3189,7 +3211,7 @@ async function attemptCreate(opts) {
3189
3211
  return newClassId;
3190
3212
  } catch {
3191
3213
  deleteClass2(newClassId);
3192
- return null;
3214
+ throw new Error("error creating class");
3193
3215
  }
3194
3216
  }
3195
3217
  async function attemptUpdate(opts) {
@@ -3201,6 +3223,7 @@ async function attemptUpdate(opts) {
3201
3223
  if (!updateProps || !update) {
3202
3224
  throw new Error("User is unable to update global classes");
3203
3225
  }
3226
+ await loadExistingClasses([classId]);
3204
3227
  const snapshot = structuredClone(stylesProvider.actions.all());
3205
3228
  try {
3206
3229
  updateProps({
@@ -3208,7 +3231,7 @@ async function attemptUpdate(opts) {
3208
3231
  props,
3209
3232
  meta: {
3210
3233
  breakpoint,
3211
- state
3234
+ state: state === "default" ? null : state
3212
3235
  }
3213
3236
  });
3214
3237
  await saveGlobalClasses2({ context: "frontend" });
@@ -3221,7 +3244,7 @@ async function attemptUpdate(opts) {
3221
3244
  });
3222
3245
  });
3223
3246
  await saveGlobalClasses2({ context: "frontend" });
3224
- return false;
3247
+ throw new Error("error updating class");
3225
3248
  }
3226
3249
  }
3227
3250
  async function attemptDelete(opts) {
@@ -3238,13 +3261,9 @@ async function attemptDelete(opts) {
3238
3261
  if (!targetClass) {
3239
3262
  throw new Error(`Class with ID "${classId}" not found`);
3240
3263
  }
3241
- try {
3242
- deleteClass2(classId);
3243
- await saveGlobalClasses2({ context: "frontend" });
3244
- return true;
3245
- } catch {
3246
- return false;
3247
- }
3264
+ deleteClass2(classId);
3265
+ await saveGlobalClasses2({ context: "frontend" });
3266
+ return true;
3248
3267
  }
3249
3268
 
3250
3269
  // src/mcp-integration/index.ts