@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 +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +83 -21
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +91 -29
- package/dist/index.mjs.map +1 -1
- package/package.json +15 -15
- package/src/audits/images-alt-text.ts +2 -1
- package/src/audits/images-inefficient-format.ts +4 -1
- package/src/audits/images-too-large.ts +4 -1
- package/src/audits/nested-boxed-containers.ts +5 -0
- package/src/components/fix-violation-with-angie.tsx +19 -2
- package/src/components/severity-icons.tsx +5 -1
- package/src/components/violation-row.tsx +68 -19
- package/src/types.ts +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-audits",
|
|
3
|
-
"version": "4.4.0-
|
|
3
|
+
"version": "4.4.0-1124",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "Elementor Team",
|
|
6
6
|
"homepage": "https://elementor.com/",
|
|
@@ -39,21 +39,21 @@
|
|
|
39
39
|
"dev": "tsup --config=../../tsup.dev.ts"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@elementor/editor": "4.4.0-
|
|
43
|
-
"@elementor/editor-mcp": "4.4.0-
|
|
44
|
-
"@elementor/editor-app-bar": "4.4.0-
|
|
45
|
-
"@elementor/editor-elements": "4.4.0-
|
|
46
|
-
"@elementor/editor-floating-panels": "4.4.0-
|
|
47
|
-
"@elementor/editor-notifications": "4.4.0-
|
|
48
|
-
"@elementor/editor-props": "4.4.0-
|
|
49
|
-
"@elementor/editor-styles": "4.4.0-
|
|
50
|
-
"@elementor/editor-v1-adapters": "4.4.0-
|
|
51
|
-
"@elementor/events": "4.4.0-
|
|
52
|
-
"@elementor/http-client": "4.4.0-
|
|
42
|
+
"@elementor/editor": "4.4.0-1124",
|
|
43
|
+
"@elementor/editor-mcp": "4.4.0-1124",
|
|
44
|
+
"@elementor/editor-app-bar": "4.4.0-1124",
|
|
45
|
+
"@elementor/editor-elements": "4.4.0-1124",
|
|
46
|
+
"@elementor/editor-floating-panels": "4.4.0-1124",
|
|
47
|
+
"@elementor/editor-notifications": "4.4.0-1124",
|
|
48
|
+
"@elementor/editor-props": "4.4.0-1124",
|
|
49
|
+
"@elementor/editor-styles": "4.4.0-1124",
|
|
50
|
+
"@elementor/editor-v1-adapters": "4.4.0-1124",
|
|
51
|
+
"@elementor/events": "4.4.0-1124",
|
|
52
|
+
"@elementor/http-client": "4.4.0-1124",
|
|
53
53
|
"@elementor/icons": "~1.77.0",
|
|
54
|
-
"@elementor/locations": "4.4.0-
|
|
55
|
-
"@elementor/session": "4.4.0-
|
|
56
|
-
"@elementor/store": "4.4.0-
|
|
54
|
+
"@elementor/locations": "4.4.0-1124",
|
|
55
|
+
"@elementor/session": "4.4.0-1124",
|
|
56
|
+
"@elementor/store": "4.4.0-1124",
|
|
57
57
|
"@elementor/ui": "1.37.5"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
@@ -17,6 +17,7 @@ export const audit: Audit = {
|
|
|
17
17
|
return { status: 'skipped', reason: __( 'No images', 'elementor' ) };
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
const isReady = ctx.pageContext.ally_plugin_active;
|
|
20
21
|
const violations: AuditViolation[] = [];
|
|
21
22
|
const failedWidgetIds = new Set< string >();
|
|
22
23
|
let missingAltImageCount = 0;
|
|
@@ -35,7 +36,7 @@ export const audit: Audit = {
|
|
|
35
36
|
elementId: node.id,
|
|
36
37
|
targetHint: 'element-settings',
|
|
37
38
|
label: __( 'Image is missing alt text.', 'elementor' ),
|
|
38
|
-
externalUrl: ctx.pageContext.ally_plugin_url,
|
|
39
|
+
externalUrl: isReady ? ctx.pageContext.ally_scan_url : ctx.pageContext.ally_plugin_url,
|
|
39
40
|
ctaLabel: __( 'Fix with Ally', 'elementor' ),
|
|
40
41
|
} );
|
|
41
42
|
}
|
|
@@ -18,6 +18,7 @@ export const audit: Audit = {
|
|
|
18
18
|
severity: 'info',
|
|
19
19
|
weight: 1,
|
|
20
20
|
evaluate: ( ctx ) => {
|
|
21
|
+
const isReady = ctx.pageContext.image_optimization_plugin_active;
|
|
21
22
|
const offendingElementIds = new Set< string >();
|
|
22
23
|
let hasAnyImage = false;
|
|
23
24
|
let inefficientImageFormatCount = 0;
|
|
@@ -57,7 +58,9 @@ export const audit: Audit = {
|
|
|
57
58
|
elementId,
|
|
58
59
|
targetHint: 'element-settings' as const,
|
|
59
60
|
label: __( "Image isn't served in a modern format like WebP or AVIF.", 'elementor' ),
|
|
60
|
-
externalUrl:
|
|
61
|
+
externalUrl: isReady
|
|
62
|
+
? ctx.pageContext.image_optimization_settings_url
|
|
63
|
+
: ctx.pageContext.image_optimization_plugin_url,
|
|
61
64
|
ctaLabel: __( 'Optimize all', 'elementor' ),
|
|
62
65
|
} ) );
|
|
63
66
|
|
|
@@ -19,6 +19,7 @@ export const audit: Audit = {
|
|
|
19
19
|
severity: 'warning',
|
|
20
20
|
weight: 7,
|
|
21
21
|
evaluate: ( ctx ) => {
|
|
22
|
+
const isReady = ctx.pageContext.image_optimization_plugin_active;
|
|
22
23
|
const widgetMaxKb = new Map< string, number >();
|
|
23
24
|
let oversizedImageCount = 0;
|
|
24
25
|
let hasAnyImage = false;
|
|
@@ -65,7 +66,9 @@ export const audit: Audit = {
|
|
|
65
66
|
__( 'Image is %d KB (over 500 KB).', 'elementor' ),
|
|
66
67
|
kb
|
|
67
68
|
),
|
|
68
|
-
externalUrl:
|
|
69
|
+
externalUrl: isReady
|
|
70
|
+
? ctx.pageContext.image_optimization_settings_url
|
|
71
|
+
: ctx.pageContext.image_optimization_plugin_url,
|
|
69
72
|
ctaLabel: __( 'Optimize all', 'elementor' ),
|
|
70
73
|
} ) );
|
|
71
74
|
|
|
@@ -35,6 +35,11 @@ export const audit: Audit = {
|
|
|
35
35
|
elementId: node.id,
|
|
36
36
|
targetHint: 'element-settings',
|
|
37
37
|
label: __( 'Nested boxed container.', 'elementor' ),
|
|
38
|
+
angieFix: true,
|
|
39
|
+
angiePrompt: __(
|
|
40
|
+
'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’s content, spacing, alignment, and hierarchy.',
|
|
41
|
+
'elementor'
|
|
42
|
+
),
|
|
38
43
|
} );
|
|
39
44
|
}
|
|
40
45
|
} );
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { isAngieAvailable, sendPromptToAngie } from '@elementor/editor-mcp';
|
|
3
3
|
import { AngieIcon } from '@elementor/icons';
|
|
4
|
-
import { IconButton, Tooltip } from '@elementor/ui';
|
|
4
|
+
import { Button, IconButton, Tooltip } from '@elementor/ui';
|
|
5
5
|
import { __ } from '@wordpress/i18n';
|
|
6
6
|
|
|
7
7
|
import { ANGIE_FIX_ENTRY_POINT, CREATE_WIDGET_EVENT } from '../constants';
|
|
@@ -9,9 +9,10 @@ import { ANGIE_FIX_ENTRY_POINT, CREATE_WIDGET_EVENT } from '../constants';
|
|
|
9
9
|
type Props = {
|
|
10
10
|
prompt: string;
|
|
11
11
|
panelZIndex: number;
|
|
12
|
+
variant?: 'icon' | 'button';
|
|
12
13
|
};
|
|
13
14
|
|
|
14
|
-
export default function FixViolationWithAngie( { prompt, panelZIndex }: Props ) {
|
|
15
|
+
export default function FixViolationWithAngie( { prompt, panelZIndex, variant = 'icon' }: Props ) {
|
|
15
16
|
const label = __( 'Fix with Angie', 'elementor' );
|
|
16
17
|
const href = `#angie-prompt=${ encodeURIComponent( prompt ) }`;
|
|
17
18
|
|
|
@@ -34,6 +35,22 @@ export default function FixViolationWithAngie( { prompt, panelZIndex }: Props )
|
|
|
34
35
|
);
|
|
35
36
|
};
|
|
36
37
|
|
|
38
|
+
if ( variant === 'button' ) {
|
|
39
|
+
return (
|
|
40
|
+
<Button
|
|
41
|
+
component="a"
|
|
42
|
+
href={ href }
|
|
43
|
+
size="small"
|
|
44
|
+
color="secondary"
|
|
45
|
+
variant="outlined"
|
|
46
|
+
startIcon={ <AngieIcon fontSize="tiny" aria-hidden={ true } /> }
|
|
47
|
+
onClick={ handleClick }
|
|
48
|
+
>
|
|
49
|
+
{ label }
|
|
50
|
+
</Button>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
37
54
|
return (
|
|
38
55
|
<Tooltip title={ label } placement="top" PopperProps={ { sx: { zIndex: panelZIndex } } }>
|
|
39
56
|
<IconButton component="a" href={ href } size="small" aria-label={ label } onClick={ handleClick }>
|
|
@@ -20,7 +20,11 @@ type Props = {
|
|
|
20
20
|
severity: AuditSeverity;
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
+
const INFO_ICON_VERTICAL_NUDGE = 'translateY(-2px)';
|
|
24
|
+
|
|
23
25
|
export default function SeverityIcon( { severity }: Props ) {
|
|
24
26
|
const { Icon, color } = SEVERITY_CONFIG[ severity ];
|
|
25
|
-
|
|
27
|
+
const sx = 'info' === severity ? { transform: INFO_ICON_VERTICAL_NUDGE } : undefined;
|
|
28
|
+
|
|
29
|
+
return <Icon fontSize="small" color={ color } sx={ sx } />;
|
|
26
30
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { getElementIcon, getElementTitle } from '@elementor/editor-elements';
|
|
3
3
|
import { useFloatingPanelZIndex } from '@elementor/editor-floating-panels';
|
|
4
|
-
import { CheckIcon, ChevronDownIcon, HelpIcon, InfoCircleIcon
|
|
4
|
+
import { CheckIcon, ChevronDownIcon, HelpIcon, InfoCircleIcon } from '@elementor/icons';
|
|
5
5
|
import { Alert, Box, Collapse, IconButton, Tooltip, Typography } from '@elementor/ui';
|
|
6
6
|
import { __ } from '@wordpress/i18n';
|
|
7
7
|
|
|
@@ -51,35 +51,67 @@ function StatusIndicator( { audit, violations }: Pick< Props, 'audit' | 'violati
|
|
|
51
51
|
return <CheckIcon fontSize="small" color="success" />;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
function GuidanceAction( {
|
|
54
|
+
function GuidanceAction( {
|
|
55
|
+
violation,
|
|
56
|
+
sharedAngiePrompt,
|
|
57
|
+
panelZIndex,
|
|
58
|
+
}: {
|
|
59
|
+
violation: AuditViolation;
|
|
60
|
+
sharedAngiePrompt?: string;
|
|
61
|
+
panelZIndex: number;
|
|
62
|
+
} ) {
|
|
55
63
|
const hasPrimaryCta = !! ( violation.ctaLabel && violation.externalUrl );
|
|
56
64
|
|
|
57
|
-
if ( ! hasPrimaryCta ) {
|
|
65
|
+
if ( ! hasPrimaryCta && ! sharedAngiePrompt ) {
|
|
58
66
|
return null;
|
|
59
67
|
}
|
|
60
68
|
|
|
61
69
|
return (
|
|
62
70
|
<Box display="flex" alignItems="center" gap={ 1 } mt={ 1 }>
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
71
|
+
{ hasPrimaryCta && (
|
|
72
|
+
<ViolationCtaButton
|
|
73
|
+
ctaLabel={ violation.ctaLabel as string }
|
|
74
|
+
externalUrl={ violation.externalUrl as string }
|
|
75
|
+
withIcon
|
|
76
|
+
/>
|
|
77
|
+
) }
|
|
78
|
+
{ hasPrimaryCta && violation.secondaryCtaLabel && violation.secondaryCtaUrl && (
|
|
69
79
|
<ViolationCtaButton
|
|
70
80
|
ctaLabel={ violation.secondaryCtaLabel }
|
|
71
81
|
externalUrl={ violation.secondaryCtaUrl }
|
|
72
82
|
variant="text"
|
|
73
83
|
/>
|
|
74
84
|
) }
|
|
85
|
+
{ sharedAngiePrompt && (
|
|
86
|
+
<FixViolationWithAngie prompt={ sharedAngiePrompt } panelZIndex={ panelZIndex } variant="button" />
|
|
87
|
+
) }
|
|
75
88
|
</Box>
|
|
76
89
|
);
|
|
77
90
|
}
|
|
78
91
|
|
|
92
|
+
function getSharedAngiePrompt( violations?: AuditViolation[] ): string | undefined {
|
|
93
|
+
if ( ! violations || violations.length < 2 ) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const [ first, ...rest ] = violations;
|
|
98
|
+
|
|
99
|
+
if ( ! first.angieFix || ! first.angiePrompt ) {
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const allShareTheSameFix = rest.every(
|
|
104
|
+
( violation ) => violation.angieFix && violation.angiePrompt === first.angiePrompt
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
return allShareTheSameFix ? first.angiePrompt : undefined;
|
|
108
|
+
}
|
|
109
|
+
|
|
79
110
|
export default function ViolationRow( { audit, expanded, onToggleExpand, skipReason, violations }: Props ) {
|
|
80
111
|
const primaryViolation = violations?.[ 0 ];
|
|
81
112
|
const isGuidanceFocusable = !! primaryViolation;
|
|
82
113
|
const panelZIndex = useFloatingPanelZIndex( AUDIT_PANEL_ID );
|
|
114
|
+
const sharedAngiePrompt = getSharedAngiePrompt( violations );
|
|
83
115
|
|
|
84
116
|
const handleGuidanceClick = () => {
|
|
85
117
|
if ( isGuidanceFocusable && primaryViolation ) {
|
|
@@ -136,7 +168,13 @@ export default function ViolationRow( { audit, expanded, onToggleExpand, skipRea
|
|
|
136
168
|
<Typography variant="caption" component="p" color="text.secondary">
|
|
137
169
|
{ audit.description }
|
|
138
170
|
</Typography>
|
|
139
|
-
{ primaryViolation &&
|
|
171
|
+
{ primaryViolation && (
|
|
172
|
+
<GuidanceAction
|
|
173
|
+
violation={ primaryViolation }
|
|
174
|
+
sharedAngiePrompt={ sharedAngiePrompt }
|
|
175
|
+
panelZIndex={ panelZIndex }
|
|
176
|
+
/>
|
|
177
|
+
) }
|
|
140
178
|
</Alert>
|
|
141
179
|
</Tooltip>
|
|
142
180
|
</Box>
|
|
@@ -145,9 +183,11 @@ export default function ViolationRow( { audit, expanded, onToggleExpand, skipRea
|
|
|
145
183
|
{ violations.map( ( violation, idx ) => {
|
|
146
184
|
const widgetIcon = violation.elementId ? getElementIcon( violation.elementId ) : null;
|
|
147
185
|
const elementTitle = violation.elementId ? getElementTitle( violation.elementId ) : null;
|
|
148
|
-
const
|
|
186
|
+
const displayLabel = elementTitle ?? violation.label;
|
|
187
|
+
const angiePromptContext = elementTitle
|
|
149
188
|
? `${ elementTitle } - ${ violation.label }`
|
|
150
189
|
: violation.label;
|
|
190
|
+
const showsOwnFixAction = !! violation.angieFix && ! sharedAngiePrompt;
|
|
151
191
|
|
|
152
192
|
return (
|
|
153
193
|
<Box
|
|
@@ -165,24 +205,33 @@ export default function ViolationRow( { audit, expanded, onToggleExpand, skipRea
|
|
|
165
205
|
borderRadius: 1,
|
|
166
206
|
cursor: 'pointer',
|
|
167
207
|
'&:hover': { bgcolor: 'action.hover' },
|
|
208
|
+
'&:hover .violation-row-fix-action, &:focus-visible .violation-row-fix-action':
|
|
209
|
+
{
|
|
210
|
+
opacity: 1,
|
|
211
|
+
},
|
|
168
212
|
} }
|
|
169
213
|
>
|
|
170
214
|
<ViolationIcon violation={ violation } widgetIcon={ widgetIcon } />
|
|
171
215
|
<Box sx={ { flex: 1 } }>
|
|
172
|
-
<Typography variant="caption">{
|
|
216
|
+
<Typography variant="caption">{ displayLabel }</Typography>
|
|
173
217
|
{ violation.detail && (
|
|
174
218
|
<Typography variant="caption" color="text.secondary">
|
|
175
219
|
{ violation.detail }
|
|
176
220
|
</Typography>
|
|
177
221
|
) }
|
|
178
222
|
</Box>
|
|
179
|
-
{
|
|
180
|
-
<
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
223
|
+
{ showsOwnFixAction && (
|
|
224
|
+
<Box
|
|
225
|
+
className="violation-row-fix-action"
|
|
226
|
+
sx={ { opacity: 0, transition: 'opacity .15s' } }
|
|
227
|
+
>
|
|
228
|
+
<FixViolationWithAngie
|
|
229
|
+
prompt={
|
|
230
|
+
violation.angiePrompt ?? buildAngiePrompt( angiePromptContext )
|
|
231
|
+
}
|
|
232
|
+
panelZIndex={ panelZIndex }
|
|
233
|
+
/>
|
|
234
|
+
</Box>
|
|
186
235
|
) }
|
|
187
236
|
</Box>
|
|
188
237
|
);
|
package/src/types.ts
CHANGED
|
@@ -72,6 +72,7 @@ export type PageContextResponse = {
|
|
|
72
72
|
ally_accessibility_statement_created: boolean;
|
|
73
73
|
ally_accessibility_statement_url: string;
|
|
74
74
|
ally_widget_settings_url: string;
|
|
75
|
+
ally_scan_url: string;
|
|
75
76
|
cookiez_plugin_active: boolean;
|
|
76
77
|
cookiez_plugin_url: string;
|
|
77
78
|
cookiez_plugin_installed: boolean;
|
|
@@ -80,6 +81,7 @@ export type PageContextResponse = {
|
|
|
80
81
|
cookiez_consent_mode_settings_url: string;
|
|
81
82
|
image_optimization_plugin_active: boolean;
|
|
82
83
|
image_optimization_plugin_url: string;
|
|
84
|
+
image_optimization_settings_url: string;
|
|
83
85
|
frontend_url: string | null;
|
|
84
86
|
site_identity: {
|
|
85
87
|
site_name_set: boolean;
|