@elementor/editor-audits 4.4.0-1122 → 4.4.0-1124

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.d.mts CHANGED
@@ -69,6 +69,7 @@ type PageContextResponse = {
69
69
  ally_accessibility_statement_created: boolean;
70
70
  ally_accessibility_statement_url: string;
71
71
  ally_widget_settings_url: string;
72
+ ally_scan_url: string;
72
73
  cookiez_plugin_active: boolean;
73
74
  cookiez_plugin_url: string;
74
75
  cookiez_plugin_installed: boolean;
@@ -77,6 +78,7 @@ type PageContextResponse = {
77
78
  cookiez_consent_mode_settings_url: string;
78
79
  image_optimization_plugin_active: boolean;
79
80
  image_optimization_plugin_url: string;
81
+ image_optimization_settings_url: string;
80
82
  frontend_url: string | null;
81
83
  site_identity: {
82
84
  site_name_set: boolean;
package/dist/index.d.ts CHANGED
@@ -69,6 +69,7 @@ type PageContextResponse = {
69
69
  ally_accessibility_statement_created: boolean;
70
70
  ally_accessibility_statement_url: string;
71
71
  ally_widget_settings_url: string;
72
+ ally_scan_url: string;
72
73
  cookiez_plugin_active: boolean;
73
74
  cookiez_plugin_url: string;
74
75
  cookiez_plugin_installed: boolean;
@@ -77,6 +78,7 @@ type PageContextResponse = {
77
78
  cookiez_consent_mode_settings_url: string;
78
79
  image_optimization_plugin_active: boolean;
79
80
  image_optimization_plugin_url: string;
81
+ image_optimization_settings_url: string;
80
82
  frontend_url: string | null;
81
83
  site_identity: {
82
84
  site_name_set: boolean;
package/dist/index.js CHANGED
@@ -1021,7 +1021,7 @@ var import_editor_mcp = require("@elementor/editor-mcp");
1021
1021
  var import_icons6 = require("@elementor/icons");
1022
1022
  var import_ui8 = require("@elementor/ui");
1023
1023
  var import_i18n9 = require("@wordpress/i18n");
1024
- function FixViolationWithAngie({ prompt, panelZIndex }) {
1024
+ function FixViolationWithAngie({ prompt, panelZIndex, variant = "icon" }) {
1025
1025
  const label = (0, import_i18n9.__)("Fix with Angie", "elementor");
1026
1026
  const href = `#angie-prompt=${encodeURIComponent(prompt)}`;
1027
1027
  const handleClick = (event) => {
@@ -1040,6 +1040,21 @@ function FixViolationWithAngie({ prompt, panelZIndex }) {
1040
1040
  })
1041
1041
  );
1042
1042
  };
1043
+ if (variant === "button") {
1044
+ return /* @__PURE__ */ React8.createElement(
1045
+ import_ui8.Button,
1046
+ {
1047
+ component: "a",
1048
+ href,
1049
+ size: "small",
1050
+ color: "secondary",
1051
+ variant: "outlined",
1052
+ startIcon: /* @__PURE__ */ React8.createElement(import_icons6.AngieIcon, { fontSize: "tiny", "aria-hidden": true }),
1053
+ onClick: handleClick
1054
+ },
1055
+ label
1056
+ );
1057
+ }
1043
1058
  return /* @__PURE__ */ React8.createElement(import_ui8.Tooltip, { title: label, placement: "top", PopperProps: { sx: { zIndex: panelZIndex } } }, /* @__PURE__ */ React8.createElement(import_ui8.IconButton, { component: "a", href, size: "small", "aria-label": label, onClick: handleClick }, /* @__PURE__ */ React8.createElement(import_icons6.AngieIcon, { fontSize: "tiny" })));
1044
1059
  }
1045
1060
 
@@ -1051,9 +1066,11 @@ var SEVERITY_CONFIG = {
1051
1066
  warning: { Icon: import_icons7.AlertCircleIcon, color: "warning" },
1052
1067
  info: { Icon: import_icons7.BulbIcon, color: "info" }
1053
1068
  };
1069
+ var INFO_ICON_VERTICAL_NUDGE = "translateY(-2px)";
1054
1070
  function SeverityIcon({ severity }) {
1055
1071
  const { Icon, color } = SEVERITY_CONFIG[severity];
1056
- return /* @__PURE__ */ React9.createElement(Icon, { fontSize: "small", color });
1072
+ const sx = "info" === severity ? { transform: INFO_ICON_VERTICAL_NUDGE } : void 0;
1073
+ return /* @__PURE__ */ React9.createElement(Icon, { fontSize: "small", color, sx });
1057
1074
  }
1058
1075
 
1059
1076
  // src/components/violation-cta-button.tsx
@@ -1114,31 +1131,49 @@ function StatusIndicator({ audit: audit26, violations }) {
1114
1131
  }
1115
1132
  return /* @__PURE__ */ React12.createElement(import_icons10.CheckIcon, { fontSize: "small", color: "success" });
1116
1133
  }
1117
- function GuidanceAction({ violation }) {
1134
+ function GuidanceAction({
1135
+ violation,
1136
+ sharedAngiePrompt,
1137
+ panelZIndex
1138
+ }) {
1118
1139
  const hasPrimaryCta = !!(violation.ctaLabel && violation.externalUrl);
1119
- if (!hasPrimaryCta) {
1140
+ if (!hasPrimaryCta && !sharedAngiePrompt) {
1120
1141
  return null;
1121
1142
  }
1122
- return /* @__PURE__ */ React12.createElement(import_ui11.Box, { display: "flex", alignItems: "center", gap: 1, mt: 1 }, /* @__PURE__ */ React12.createElement(
1143
+ return /* @__PURE__ */ React12.createElement(import_ui11.Box, { display: "flex", alignItems: "center", gap: 1, mt: 1 }, hasPrimaryCta && /* @__PURE__ */ React12.createElement(
1123
1144
  ViolationCtaButton,
1124
1145
  {
1125
1146
  ctaLabel: violation.ctaLabel,
1126
1147
  externalUrl: violation.externalUrl,
1127
1148
  withIcon: true
1128
1149
  }
1129
- ), violation.secondaryCtaLabel && violation.secondaryCtaUrl && /* @__PURE__ */ React12.createElement(
1150
+ ), hasPrimaryCta && violation.secondaryCtaLabel && violation.secondaryCtaUrl && /* @__PURE__ */ React12.createElement(
1130
1151
  ViolationCtaButton,
1131
1152
  {
1132
1153
  ctaLabel: violation.secondaryCtaLabel,
1133
1154
  externalUrl: violation.secondaryCtaUrl,
1134
1155
  variant: "text"
1135
1156
  }
1136
- ));
1157
+ ), sharedAngiePrompt && /* @__PURE__ */ React12.createElement(FixViolationWithAngie, { prompt: sharedAngiePrompt, panelZIndex, variant: "button" }));
1158
+ }
1159
+ function getSharedAngiePrompt(violations) {
1160
+ if (!violations || violations.length < 2) {
1161
+ return void 0;
1162
+ }
1163
+ const [first, ...rest] = violations;
1164
+ if (!first.angieFix || !first.angiePrompt) {
1165
+ return void 0;
1166
+ }
1167
+ const allShareTheSameFix = rest.every(
1168
+ (violation) => violation.angieFix && violation.angiePrompt === first.angiePrompt
1169
+ );
1170
+ return allShareTheSameFix ? first.angiePrompt : void 0;
1137
1171
  }
1138
1172
  function ViolationRow({ audit: audit26, expanded, onToggleExpand, skipReason, violations }) {
1139
1173
  const primaryViolation = violations?.[0];
1140
1174
  const isGuidanceFocusable = !!primaryViolation;
1141
1175
  const panelZIndex = (0, import_editor_floating_panels2.useFloatingPanelZIndex)(AUDIT_PANEL_ID);
1176
+ const sharedAngiePrompt = getSharedAngiePrompt(violations);
1142
1177
  const handleGuidanceClick = () => {
1143
1178
  if (isGuidanceFocusable && primaryViolation) {
1144
1179
  focusViolation(primaryViolation);
@@ -1188,11 +1223,20 @@ function ViolationRow({ audit: audit26, expanded, onToggleExpand, skipReason, vi
1188
1223
  onKeyDown: isGuidanceFocusable ? onKeyboardClick(handleGuidanceClick) : void 0
1189
1224
  },
1190
1225
  /* @__PURE__ */ React12.createElement(import_ui11.Typography, { variant: "caption", component: "p", color: "text.secondary" }, audit26.description),
1191
- primaryViolation && /* @__PURE__ */ React12.createElement(GuidanceAction, { violation: primaryViolation })
1226
+ primaryViolation && /* @__PURE__ */ React12.createElement(
1227
+ GuidanceAction,
1228
+ {
1229
+ violation: primaryViolation,
1230
+ sharedAngiePrompt,
1231
+ panelZIndex
1232
+ }
1233
+ )
1192
1234
  ))), violations && violations.length > 0 && /* @__PURE__ */ React12.createElement(import_ui11.Box, { role: "list", sx: { paddingBlockEnd: 1 } }, violations.map((violation, idx) => {
1193
1235
  const widgetIcon = violation.elementId ? (0, import_editor_elements5.getElementIcon)(violation.elementId) : null;
1194
1236
  const elementTitle = violation.elementId ? (0, import_editor_elements5.getElementTitle)(violation.elementId) : null;
1195
- const rowLabel = elementTitle ? `${elementTitle} - ${violation.label}` : violation.label;
1237
+ const displayLabel = elementTitle ?? violation.label;
1238
+ const angiePromptContext = elementTitle ? `${elementTitle} - ${violation.label}` : violation.label;
1239
+ const showsOwnFixAction = !!violation.angieFix && !sharedAngiePrompt;
1196
1240
  return /* @__PURE__ */ React12.createElement(
1197
1241
  import_ui11.Box,
1198
1242
  {
@@ -1209,18 +1253,28 @@ function ViolationRow({ audit: audit26, expanded, onToggleExpand, skipReason, vi
1209
1253
  paddingInline: 1,
1210
1254
  borderRadius: 1,
1211
1255
  cursor: "pointer",
1212
- "&:hover": { bgcolor: "action.hover" }
1256
+ "&:hover": { bgcolor: "action.hover" },
1257
+ "&:hover .violation-row-fix-action, &:focus-visible .violation-row-fix-action": {
1258
+ opacity: 1
1259
+ }
1213
1260
  }
1214
1261
  },
1215
1262
  /* @__PURE__ */ React12.createElement(ViolationIcon, { violation, widgetIcon }),
1216
- /* @__PURE__ */ React12.createElement(import_ui11.Box, { sx: { flex: 1 } }, /* @__PURE__ */ React12.createElement(import_ui11.Typography, { variant: "caption" }, rowLabel), violation.detail && /* @__PURE__ */ React12.createElement(import_ui11.Typography, { variant: "caption", color: "text.secondary" }, violation.detail)),
1217
- violation.angieFix ? /* @__PURE__ */ React12.createElement(
1218
- FixViolationWithAngie,
1263
+ /* @__PURE__ */ React12.createElement(import_ui11.Box, { sx: { flex: 1 } }, /* @__PURE__ */ React12.createElement(import_ui11.Typography, { variant: "caption" }, displayLabel), violation.detail && /* @__PURE__ */ React12.createElement(import_ui11.Typography, { variant: "caption", color: "text.secondary" }, violation.detail)),
1264
+ showsOwnFixAction && /* @__PURE__ */ React12.createElement(
1265
+ import_ui11.Box,
1219
1266
  {
1220
- prompt: violation.angiePrompt ?? buildAngiePrompt(rowLabel),
1221
- panelZIndex
1222
- }
1223
- ) : /* @__PURE__ */ React12.createElement(import_icons10.WandIcon, { fontSize: "tiny", "aria-hidden": true })
1267
+ className: "violation-row-fix-action",
1268
+ sx: { opacity: 0, transition: "opacity .15s" }
1269
+ },
1270
+ /* @__PURE__ */ React12.createElement(
1271
+ FixViolationWithAngie,
1272
+ {
1273
+ prompt: violation.angiePrompt ?? buildAngiePrompt(angiePromptContext),
1274
+ panelZIndex
1275
+ }
1276
+ )
1277
+ )
1224
1278
  );
1225
1279
  }))));
1226
1280
  }
@@ -2268,6 +2322,7 @@ var audit11 = {
2268
2322
  if (!hasPageImages(ctx.elements.tree)) {
2269
2323
  return { status: "skipped", reason: (0, import_i18n29.__)("No images", "elementor") };
2270
2324
  }
2325
+ const isReady = ctx.pageContext.ally_plugin_active;
2271
2326
  const violations = [];
2272
2327
  const failedWidgetIds = /* @__PURE__ */ new Set();
2273
2328
  let missingAltImageCount = 0;
@@ -2283,7 +2338,7 @@ var audit11 = {
2283
2338
  elementId: node.id,
2284
2339
  targetHint: "element-settings",
2285
2340
  label: (0, import_i18n29.__)("Image is missing alt text.", "elementor"),
2286
- externalUrl: ctx.pageContext.ally_plugin_url,
2341
+ externalUrl: isReady ? ctx.pageContext.ally_scan_url : ctx.pageContext.ally_plugin_url,
2287
2342
  ctaLabel: (0, import_i18n29.__)("Fix with Ally", "elementor")
2288
2343
  });
2289
2344
  }
@@ -2304,6 +2359,7 @@ var audit12 = {
2304
2359
  severity: "info",
2305
2360
  weight: 1,
2306
2361
  evaluate: (ctx) => {
2362
+ const isReady = ctx.pageContext.image_optimization_plugin_active;
2307
2363
  const offendingElementIds = /* @__PURE__ */ new Set();
2308
2364
  let hasAnyImage = false;
2309
2365
  let inefficientImageFormatCount = 0;
@@ -2334,7 +2390,7 @@ var audit12 = {
2334
2390
  elementId,
2335
2391
  targetHint: "element-settings",
2336
2392
  label: (0, import_i18n30.__)("Image isn't served in a modern format like WebP or AVIF.", "elementor"),
2337
- externalUrl: ctx.pageContext.image_optimization_plugin_url,
2393
+ externalUrl: isReady ? ctx.pageContext.image_optimization_settings_url : ctx.pageContext.image_optimization_plugin_url,
2338
2394
  ctaLabel: (0, import_i18n30.__)("Optimize all", "elementor")
2339
2395
  }));
2340
2396
  return violations.length === 0 ? { status: "pass" } : { status: "fail", violations, metadata: { inefficientImageFormatCount } };
@@ -2354,6 +2410,7 @@ var audit13 = {
2354
2410
  severity: "warning",
2355
2411
  weight: 7,
2356
2412
  evaluate: (ctx) => {
2413
+ const isReady = ctx.pageContext.image_optimization_plugin_active;
2357
2414
  const widgetMaxKb = /* @__PURE__ */ new Map();
2358
2415
  let oversizedImageCount = 0;
2359
2416
  let hasAnyImage = false;
@@ -2390,7 +2447,7 @@ var audit13 = {
2390
2447
  (0, import_i18n31.__)("Image is %d KB (over 500 KB).", "elementor"),
2391
2448
  kb
2392
2449
  ),
2393
- externalUrl: ctx.pageContext.image_optimization_plugin_url,
2450
+ externalUrl: isReady ? ctx.pageContext.image_optimization_settings_url : ctx.pageContext.image_optimization_plugin_url,
2394
2451
  ctaLabel: (0, import_i18n31.__)("Optimize all", "elementor")
2395
2452
  }));
2396
2453
  return violations.length === 0 ? { status: "pass" } : { status: "fail", violations, metadata: { oversizedImageCount } };
@@ -2425,7 +2482,12 @@ var audit14 = {
2425
2482
  auditId: audit14.id,
2426
2483
  elementId: node.id,
2427
2484
  targetHint: "element-settings",
2428
- label: (0, import_i18n32.__)("Nested boxed container.", "elementor")
2485
+ label: (0, import_i18n32.__)("Nested boxed container.", "elementor"),
2486
+ angieFix: true,
2487
+ angiePrompt: (0, import_i18n32.__)(
2488
+ "Find containers that have nested containers. Containers can be deep-nested. Update the nested container styling so that when a parent container already uses a boxed setting, any inner container inside it is set to Full Width. Keep the first parent container boxed, remove all boxed styling from the nested inner containers, and preserve the inner container\u2019s content, spacing, alignment, and hierarchy.",
2489
+ "elementor"
2490
+ )
2429
2491
  });
2430
2492
  }
2431
2493
  });