astro 4.4.14 → 4.5.0
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/components/Code.astro +15 -12
- package/dist/@types/astro.d.ts +95 -18
- package/dist/assets/utils/getAssetsPrefix.d.ts +2 -0
- package/dist/assets/utils/getAssetsPrefix.js +14 -0
- package/dist/assets/vite-plugin-assets.js +10 -3
- package/dist/cli/add/index.js +76 -28
- package/dist/cli/install-package.js +2 -2
- package/dist/content/types-generator.js +56 -7
- package/dist/content/vite-plugin-content-assets.js +11 -3
- package/dist/core/app/common.js +2 -0
- package/dist/core/app/index.js +10 -2
- package/dist/core/app/types.d.ts +7 -2
- package/dist/core/base-pipeline.d.ts +2 -1
- package/dist/core/base-pipeline.js +2 -1
- package/dist/core/build/generate.js +1 -0
- package/dist/core/build/internal.d.ts +6 -0
- package/dist/core/build/internal.js +1 -0
- package/dist/core/build/plugins/index.js +6 -1
- package/dist/core/build/plugins/plugin-analyzer.js +10 -98
- package/dist/core/build/plugins/plugin-css.js +27 -1
- package/dist/core/build/plugins/plugin-manifest.js +5 -2
- package/dist/core/build/plugins/plugin-scripts.d.ts +8 -0
- package/dist/core/build/plugins/plugin-scripts.js +34 -0
- package/dist/core/compile/compile.d.ts +1 -7
- package/dist/core/compile/compile.js +5 -4
- package/dist/core/compile/style.d.ts +4 -3
- package/dist/core/compile/style.js +5 -4
- package/dist/core/compile/types.d.ts +11 -0
- package/dist/core/config/schema.d.ts +177 -113
- package/dist/core/config/schema.js +42 -9
- package/dist/core/config/vite-load.js +1 -0
- package/dist/core/constants.d.ts +1 -0
- package/dist/core/constants.js +3 -1
- package/dist/core/create-vite.js +5 -3
- package/dist/core/dev/dev.js +1 -1
- package/dist/core/errors/dev/vite.js +1 -1
- package/dist/core/messages.js +2 -2
- package/dist/core/render/params-and-props.js +2 -1
- package/dist/core/render/ssr-element.d.ts +8 -8
- package/dist/core/render/ssr-element.js +4 -2
- package/dist/core/render-context.js +3 -1
- package/dist/core/routing/astro-designed-error-pages.d.ts +2 -0
- package/dist/core/routing/astro-designed-error-pages.js +21 -0
- package/dist/runtime/client/dev-toolbar/apps/audit/index.d.ts +8 -15
- package/dist/runtime/client/dev-toolbar/apps/audit/index.js +130 -249
- package/dist/runtime/client/dev-toolbar/apps/audit/{a11y.js → rules/a11y.js} +4 -2
- package/dist/runtime/client/dev-toolbar/apps/audit/rules/index.d.ts +35 -0
- package/dist/runtime/client/dev-toolbar/apps/audit/rules/index.js +40 -0
- package/dist/runtime/client/dev-toolbar/apps/audit/{perf.js → rules/perf.js} +2 -2
- package/dist/runtime/client/dev-toolbar/apps/audit/ui/audit-list-item.d.ts +7 -0
- package/dist/runtime/client/dev-toolbar/apps/audit/ui/audit-list-item.js +137 -0
- package/dist/runtime/client/dev-toolbar/apps/audit/ui/audit-list-window.d.ts +23 -0
- package/dist/runtime/client/dev-toolbar/apps/audit/ui/audit-list-window.js +384 -0
- package/dist/runtime/client/dev-toolbar/apps/audit/ui/audit-ui.d.ts +6 -0
- package/dist/runtime/client/dev-toolbar/apps/audit/ui/audit-ui.js +126 -0
- package/dist/runtime/client/dev-toolbar/apps/utils/window.d.ts +1 -1
- package/dist/runtime/client/dev-toolbar/apps/utils/window.js +3 -1
- package/dist/runtime/client/dev-toolbar/entrypoint.js +43 -15
- package/dist/runtime/client/dev-toolbar/settings.d.ts +3 -1
- package/dist/runtime/client/dev-toolbar/settings.js +8 -2
- package/dist/runtime/client/dev-toolbar/toolbar.d.ts +1 -0
- package/dist/runtime/client/dev-toolbar/toolbar.js +10 -8
- package/dist/runtime/client/dev-toolbar/ui-library/badge.d.ts +14 -4
- package/dist/runtime/client/dev-toolbar/ui-library/badge.js +72 -33
- package/dist/runtime/client/dev-toolbar/ui-library/button.d.ts +14 -4
- package/dist/runtime/client/dev-toolbar/ui-library/button.js +100 -47
- package/dist/runtime/client/dev-toolbar/ui-library/card.d.ts +9 -0
- package/dist/runtime/client/dev-toolbar/ui-library/card.js +57 -2
- package/dist/runtime/client/dev-toolbar/ui-library/highlight.d.ts +9 -0
- package/dist/runtime/client/dev-toolbar/ui-library/highlight.js +54 -2
- package/dist/runtime/client/dev-toolbar/ui-library/icons.d.ts +4 -0
- package/dist/runtime/client/dev-toolbar/ui-library/icons.js +5 -1
- package/dist/runtime/client/dev-toolbar/ui-library/toggle.d.ts +9 -0
- package/dist/runtime/client/dev-toolbar/ui-library/toggle.js +64 -5
- package/dist/runtime/compiler/index.d.ts +1 -1
- package/dist/runtime/compiler/index.js +2 -0
- package/dist/runtime/server/hydration.js +3 -2
- package/dist/runtime/server/index.d.ts +1 -1
- package/dist/runtime/server/index.js +2 -0
- package/dist/runtime/server/render/astro/factory.d.ts +1 -1
- package/dist/runtime/server/render/component.js +4 -5
- package/dist/runtime/server/render/index.d.ts +1 -0
- package/dist/runtime/server/render/index.js +2 -0
- package/dist/runtime/server/render/script.d.ts +6 -0
- package/dist/runtime/server/render/script.js +15 -0
- package/dist/transitions/router.js +12 -3
- package/dist/vite-plugin-astro/index.d.ts +2 -2
- package/dist/vite-plugin-astro/index.js +12 -1
- package/dist/vite-plugin-astro/types.d.ts +21 -1
- package/dist/vite-plugin-astro-server/pipeline.js +6 -2
- package/dist/vite-plugin-astro-server/plugin.js +6 -2
- package/dist/vite-plugin-astro-server/response.d.ts +6 -0
- package/dist/vite-plugin-astro-server/response.js +13 -0
- package/dist/vite-plugin-astro-server/route.js +18 -2
- package/package.json +8 -9
- package/tsconfigs/base.json +3 -1
- /package/dist/runtime/client/dev-toolbar/apps/audit/{a11y.d.ts → rules/a11y.d.ts} +0 -0
- /package/dist/runtime/client/dev-toolbar/apps/audit/{perf.d.ts → rules/perf.d.ts} +0 -0
|
@@ -1,25 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
} from "
|
|
8
|
-
import { closeOnOutsideClick, createWindowElement } from "../utils/window.js";
|
|
9
|
-
import { a11y } from "./a11y.js";
|
|
10
|
-
import { perf } from "./perf.js";
|
|
1
|
+
import { settings } from "../../settings.js";
|
|
2
|
+
import { positionHighlight } from "../utils/highlight.js";
|
|
3
|
+
import { closeOnOutsideClick } from "../utils/window.js";
|
|
4
|
+
import { rulesCategories } from "./rules/index.js";
|
|
5
|
+
import { DevToolbarAuditListItem } from "./ui/audit-list-item.js";
|
|
6
|
+
import { DevToolbarAuditListWindow } from "./ui/audit-list-window.js";
|
|
7
|
+
import { createAuditUI } from "./ui/audit-ui.js";
|
|
11
8
|
const icon = '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 1 20 16"><path fill="#fff" d="M.6 2A1.1 1.1 0 0 1 1.7.9h16.6a1.1 1.1 0 1 1 0 2.2H1.6A1.1 1.1 0 0 1 .8 2Zm1.1 7.1h6a1.1 1.1 0 0 0 0-2.2h-6a1.1 1.1 0 0 0 0 2.2ZM9.3 13H1.8a1.1 1.1 0 1 0 0 2.2h7.5a1.1 1.1 0 1 0 0-2.2Zm11.3 1.9a1.1 1.1 0 0 1-1.5 0l-1.7-1.7a4.1 4.1 0 1 1 1.6-1.6l1.6 1.7a1.1 1.1 0 0 1 0 1.6Zm-5.3-3.4a1.9 1.9 0 1 0 0-3.8 1.9 1.9 0 0 0 0 3.8Z"/></svg>';
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
for (const key of dynamicAuditRuleKeys) {
|
|
17
|
-
const value = rule[key];
|
|
18
|
-
if (typeof value === "string")
|
|
19
|
-
continue;
|
|
20
|
-
resolved[key] = value(element);
|
|
21
|
-
}
|
|
22
|
-
return resolved;
|
|
9
|
+
try {
|
|
10
|
+
customElements.define("astro-dev-toolbar-audit-window", DevToolbarAuditListWindow);
|
|
11
|
+
customElements.define("astro-dev-toolbar-audit-list-item", DevToolbarAuditListItem);
|
|
12
|
+
} catch (e) {
|
|
23
13
|
}
|
|
24
14
|
var audit_default = {
|
|
25
15
|
id: "astro:audit",
|
|
@@ -27,201 +17,116 @@ var audit_default = {
|
|
|
27
17
|
icon,
|
|
28
18
|
async init(canvas, eventTarget) {
|
|
29
19
|
let audits = [];
|
|
20
|
+
let auditWindow = document.createElement(
|
|
21
|
+
"astro-dev-toolbar-audit-window"
|
|
22
|
+
);
|
|
23
|
+
let hasCreatedUI = false;
|
|
24
|
+
canvas.appendChild(auditWindow);
|
|
30
25
|
await lint();
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
matches = Array.from(elements);
|
|
26
|
+
let mutationDebounce;
|
|
27
|
+
const observer = new MutationObserver(() => {
|
|
28
|
+
if (mutationDebounce) {
|
|
29
|
+
clearTimeout(mutationDebounce);
|
|
30
|
+
}
|
|
31
|
+
mutationDebounce = setTimeout(() => {
|
|
32
|
+
settings.logger.verboseLog("Rerunning audit lints because the DOM has been updated.");
|
|
33
|
+
if ("requestIdleCallback" in window) {
|
|
34
|
+
window.requestIdleCallback(
|
|
35
|
+
async () => {
|
|
36
|
+
lint();
|
|
37
|
+
},
|
|
38
|
+
{ timeout: 300 }
|
|
39
|
+
);
|
|
46
40
|
} else {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
for (const element of matches) {
|
|
54
|
-
if (audits.some((audit) => audit.auditedElement === element))
|
|
55
|
-
continue;
|
|
56
|
-
await createAuditProblem(rule, element);
|
|
41
|
+
setTimeout(() => {
|
|
42
|
+
lint();
|
|
43
|
+
}, 150);
|
|
57
44
|
}
|
|
45
|
+
}, 250);
|
|
46
|
+
});
|
|
47
|
+
setupObserver();
|
|
48
|
+
document.addEventListener("astro:before-preparation", () => {
|
|
49
|
+
observer.disconnect();
|
|
50
|
+
});
|
|
51
|
+
document.addEventListener("astro:after-swap", async () => {
|
|
52
|
+
lint();
|
|
53
|
+
});
|
|
54
|
+
document.addEventListener("astro:page-load", async () => {
|
|
55
|
+
refreshLintPositions();
|
|
56
|
+
setTimeout(() => {
|
|
57
|
+
setupObserver();
|
|
58
|
+
}, 100);
|
|
59
|
+
});
|
|
60
|
+
eventTarget.addEventListener("app-toggled", (event) => {
|
|
61
|
+
if (event.detail.state === true) {
|
|
62
|
+
createAuditsUI();
|
|
58
63
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
})
|
|
66
|
-
);
|
|
67
|
-
const auditListWindow = createWindowElement(
|
|
68
|
-
`
|
|
69
|
-
<style>
|
|
70
|
-
astro-dev-toolbar-window {
|
|
71
|
-
left: initial;
|
|
72
|
-
top: 8px;
|
|
73
|
-
right: 8px;
|
|
74
|
-
transform: none;
|
|
75
|
-
width: 320px;
|
|
76
|
-
max-height: 320px;
|
|
77
|
-
padding: 0;
|
|
78
|
-
overflow: hidden;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
hr {
|
|
82
|
-
margin: 0;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
header {
|
|
86
|
-
display: flex;
|
|
87
|
-
justify-content: space-between;
|
|
88
|
-
align-items: center;
|
|
89
|
-
padding: 18px;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
h1 {
|
|
93
|
-
font-size: 22px;
|
|
94
|
-
font-weight: 600;
|
|
95
|
-
color: #fff;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
ul, li {
|
|
99
|
-
margin: 0;
|
|
100
|
-
padding: 0;
|
|
101
|
-
list-style: none;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
h1, h2 {
|
|
105
|
-
margin: 0;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
h3 {
|
|
109
|
-
margin: 0;
|
|
110
|
-
margin-bottom: 8px;
|
|
111
|
-
color: white;
|
|
112
|
-
white-space: nowrap;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
.audit-title {
|
|
116
|
-
font-weight: bold;
|
|
117
|
-
color: white;
|
|
118
|
-
margin-right: 1ch;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
#audit-list {
|
|
122
|
-
display: flex;
|
|
123
|
-
flex-direction: column;
|
|
124
|
-
overflow: auto;
|
|
125
|
-
}
|
|
126
|
-
</style>
|
|
127
|
-
|
|
128
|
-
<header>
|
|
129
|
-
<h1>Audits</h1>
|
|
130
|
-
<astro-dev-toolbar-badge size="large">${audits.length} problem${audits.length > 1 ? "s" : ""} found</astro-dev-toolbar-badge>
|
|
131
|
-
</header>
|
|
132
|
-
<hr />`
|
|
133
|
-
);
|
|
134
|
-
const auditListUl = document.createElement("ul");
|
|
135
|
-
auditListUl.id = "audit-list";
|
|
136
|
-
audits.forEach((audit, index) => {
|
|
137
|
-
const resolvedRule = resolveAuditRule(audit.rule, audit.auditedElement);
|
|
138
|
-
const card = document.createElement("astro-dev-toolbar-card");
|
|
139
|
-
card.shadowRoot.innerHTML = `
|
|
140
|
-
<style>
|
|
141
|
-
:host>button {
|
|
142
|
-
text-align: left;
|
|
143
|
-
box-shadow: none !important;
|
|
144
|
-
${index + 1 < audits.length ? "border-radius: 0 !important;" : "border-radius: 0 0 8px 8px !important;"}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
:host>button:hover {
|
|
148
|
-
cursor: pointer;
|
|
149
|
-
}
|
|
150
|
-
</style>`;
|
|
151
|
-
card.clickAction = () => {
|
|
152
|
-
audit.highlightElement.scrollIntoView();
|
|
153
|
-
audit.highlightElement.focus();
|
|
154
|
-
};
|
|
155
|
-
const h3 = document.createElement("h3");
|
|
156
|
-
h3.innerText = finder(audit.auditedElement);
|
|
157
|
-
card.appendChild(h3);
|
|
158
|
-
const div = document.createElement("div");
|
|
159
|
-
const title = document.createElement("span");
|
|
160
|
-
title.classList.add("audit-title");
|
|
161
|
-
title.innerHTML = resolvedRule.title;
|
|
162
|
-
div.appendChild(title);
|
|
163
|
-
card.appendChild(div);
|
|
164
|
-
auditListUl.appendChild(card);
|
|
64
|
+
});
|
|
65
|
+
closeOnOutsideClick(eventTarget, () => {
|
|
66
|
+
const activeAudits = audits.filter((audit) => audit.card?.hasAttribute("active"));
|
|
67
|
+
if (activeAudits.length > 0) {
|
|
68
|
+
activeAudits.forEach((audit) => {
|
|
69
|
+
audit.card?.toggleAttribute("active", false);
|
|
165
70
|
});
|
|
166
|
-
|
|
167
|
-
canvas.append(auditListWindow);
|
|
168
|
-
} else {
|
|
169
|
-
eventTarget.dispatchEvent(
|
|
170
|
-
new CustomEvent("toggle-notification", {
|
|
171
|
-
detail: {
|
|
172
|
-
state: false
|
|
173
|
-
}
|
|
174
|
-
})
|
|
175
|
-
);
|
|
176
|
-
const window2 = createWindowElement(
|
|
177
|
-
`<style>
|
|
178
|
-
header {
|
|
179
|
-
display: flex;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
h1 {
|
|
183
|
-
display: flex;
|
|
184
|
-
align-items: center;
|
|
185
|
-
gap: 8px;
|
|
186
|
-
font-weight: 600;
|
|
187
|
-
color: #fff;
|
|
188
|
-
margin: 0;
|
|
189
|
-
font-size: 22px;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
astro-dev-toolbar-icon {
|
|
193
|
-
width: 1em;
|
|
194
|
-
height: 1em;
|
|
195
|
-
padding: 8px;
|
|
196
|
-
display: block;
|
|
197
|
-
background: green;
|
|
198
|
-
border-radius: 9999px;
|
|
199
|
-
}
|
|
200
|
-
</style>
|
|
201
|
-
<header>
|
|
202
|
-
<h1><astro-dev-toolbar-icon icon="check-circle"></astro-dev-toolbar-icon>No accessibility or performance issues detected.</h1>
|
|
203
|
-
</header>
|
|
204
|
-
<p>
|
|
205
|
-
Nice work! This app scans the page and highlights common accessibility and performance issues for you, like a missing "alt" attribute on an image, or a image not using performant attributes.
|
|
206
|
-
</p>
|
|
207
|
-
`
|
|
208
|
-
);
|
|
209
|
-
canvas.append(window2);
|
|
71
|
+
return true;
|
|
210
72
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
73
|
+
return false;
|
|
74
|
+
});
|
|
75
|
+
async function createAuditsUI() {
|
|
76
|
+
if (hasCreatedUI)
|
|
77
|
+
return;
|
|
78
|
+
const fragment = document.createDocumentFragment();
|
|
79
|
+
for (const audit of audits) {
|
|
80
|
+
const { card, highlight } = createAuditUI(audit, audits);
|
|
81
|
+
audit.card = card;
|
|
82
|
+
audit.highlight = highlight;
|
|
83
|
+
fragment.appendChild(highlight);
|
|
84
|
+
}
|
|
85
|
+
auditWindow.audits = audits;
|
|
86
|
+
canvas.appendChild(fragment);
|
|
87
|
+
hasCreatedUI = true;
|
|
214
88
|
}
|
|
215
|
-
function
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
89
|
+
async function lint() {
|
|
90
|
+
if (audits.length > 0) {
|
|
91
|
+
audits.forEach((audit) => {
|
|
92
|
+
audit.highlight?.remove();
|
|
93
|
+
audit.card?.remove();
|
|
94
|
+
});
|
|
95
|
+
audits = [];
|
|
96
|
+
hasCreatedUI = false;
|
|
220
97
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
98
|
+
const selectorCache = /* @__PURE__ */ new Map();
|
|
99
|
+
for (const ruleCategory of rulesCategories) {
|
|
100
|
+
for (const rule of ruleCategory.rules) {
|
|
101
|
+
const elements = selectorCache.get(rule.selector) ?? document.querySelectorAll(rule.selector);
|
|
102
|
+
let matches = [];
|
|
103
|
+
if (typeof rule.match === "undefined") {
|
|
104
|
+
matches = Array.from(elements);
|
|
105
|
+
} else {
|
|
106
|
+
for (const element of elements) {
|
|
107
|
+
try {
|
|
108
|
+
if (await rule.match(element)) {
|
|
109
|
+
matches.push(element);
|
|
110
|
+
}
|
|
111
|
+
} catch (e) {
|
|
112
|
+
settings.logger.error(`Error while running audit's match function: ${e}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
for (const element of matches) {
|
|
117
|
+
if (audits.some((audit) => audit.auditedElement === element))
|
|
118
|
+
continue;
|
|
119
|
+
await createAuditProblem(rule, element);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
eventTarget.dispatchEvent(
|
|
124
|
+
new CustomEvent("toggle-notification", {
|
|
125
|
+
detail: {
|
|
126
|
+
state: audits.length > 0
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
);
|
|
225
130
|
}
|
|
226
131
|
async function createAuditProblem(rule, originalElement) {
|
|
227
132
|
const computedStyle = window.getComputedStyle(originalElement);
|
|
@@ -232,52 +137,28 @@ var audit_default = {
|
|
|
232
137
|
if (originalElement.nodeName === "IMG" && !originalElement.complete) {
|
|
233
138
|
return;
|
|
234
139
|
}
|
|
235
|
-
const rect = originalElement.getBoundingClientRect();
|
|
236
|
-
const highlight = createHighlight(rect, "warning", { "data-audit-code": rule.code });
|
|
237
|
-
const tooltip = buildAuditTooltip(rule, originalElement);
|
|
238
|
-
const { isFixed } = getElementsPositionInDocument(originalElement);
|
|
239
|
-
if (isFixed) {
|
|
240
|
-
tooltip.style.position = highlight.style.position = "fixed";
|
|
241
|
-
}
|
|
242
|
-
attachTooltipToHighlight(highlight, tooltip, originalElement);
|
|
243
|
-
canvas.append(highlight);
|
|
244
140
|
audits.push({
|
|
245
|
-
highlightElement: highlight,
|
|
246
141
|
auditedElement: originalElement,
|
|
247
|
-
rule
|
|
142
|
+
rule,
|
|
143
|
+
card: null,
|
|
144
|
+
highlight: null
|
|
248
145
|
});
|
|
249
146
|
}
|
|
250
|
-
function
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
title: escapeHtml(title)
|
|
257
|
-
},
|
|
258
|
-
{
|
|
259
|
-
content: escapeHtml(message)
|
|
260
|
-
}
|
|
261
|
-
];
|
|
262
|
-
const elementFile = element.getAttribute("data-astro-source-file");
|
|
263
|
-
const elementPosition = element.getAttribute("data-astro-source-loc");
|
|
264
|
-
if (elementFile) {
|
|
265
|
-
const elementFileWithPosition = elementFile + (elementPosition ? ":" + elementPosition : "");
|
|
266
|
-
tooltip.sections.push({
|
|
267
|
-
content: elementFileWithPosition.slice(
|
|
268
|
-
window.__astro_dev_toolbar__.root.length - 1
|
|
269
|
-
// We want to keep the final slash, so minus one.
|
|
270
|
-
),
|
|
271
|
-
clickDescription: "Click to go to file",
|
|
272
|
-
async clickAction() {
|
|
273
|
-
await fetch("/__open-in-editor?file=" + encodeURIComponent(elementFileWithPosition));
|
|
274
|
-
}
|
|
275
|
-
});
|
|
276
|
-
}
|
|
277
|
-
return tooltip;
|
|
147
|
+
function refreshLintPositions() {
|
|
148
|
+
audits.forEach(({ highlight, auditedElement }) => {
|
|
149
|
+
const rect = auditedElement.getBoundingClientRect();
|
|
150
|
+
if (highlight)
|
|
151
|
+
positionHighlight(highlight, rect);
|
|
152
|
+
});
|
|
278
153
|
}
|
|
279
|
-
|
|
280
|
-
|
|
154
|
+
["scroll", "resize"].forEach((event) => {
|
|
155
|
+
window.addEventListener(event, refreshLintPositions);
|
|
156
|
+
});
|
|
157
|
+
function setupObserver() {
|
|
158
|
+
observer.observe(document.body, {
|
|
159
|
+
childList: true,
|
|
160
|
+
subtree: true
|
|
161
|
+
});
|
|
281
162
|
}
|
|
282
163
|
}
|
|
283
164
|
};
|
|
@@ -262,8 +262,8 @@ const a11y = [
|
|
|
262
262
|
}
|
|
263
263
|
},
|
|
264
264
|
{
|
|
265
|
-
code: "a11y-invalid-
|
|
266
|
-
title: "
|
|
265
|
+
code: "a11y-invalid-href",
|
|
266
|
+
title: "Invalid `href` attribute",
|
|
267
267
|
message: "`href` should not be empty, `'#'`, or `javascript:`.",
|
|
268
268
|
selector: 'a[href]:is([href=""], [href="#"], [href^="javascript:" i])'
|
|
269
269
|
},
|
|
@@ -306,6 +306,7 @@ const a11y = [
|
|
|
306
306
|
{
|
|
307
307
|
code: "a11y-missing-attribute",
|
|
308
308
|
title: "Required attributes missing.",
|
|
309
|
+
description: "Some HTML elements require additional attributes for accessibility. For example, an `img` element requires an `alt` attribute, this attribute is used to describe the content of the image for screen readers.",
|
|
309
310
|
message: (element) => {
|
|
310
311
|
const requiredAttributes = a11y_required_attributes[element.localName];
|
|
311
312
|
const missingAttributes = requiredAttributes.filter(
|
|
@@ -448,6 +449,7 @@ const a11y = [
|
|
|
448
449
|
{
|
|
449
450
|
code: "a11y-no-noninteractive-tabindex",
|
|
450
451
|
title: "Invalid `tabindex` on non-interactive element",
|
|
452
|
+
description: 'The `tabindex` attribute should only be used on interactive elements, as it can be confusing for keyboard-only users to navigate through non-interactive elements. If your element is only conditionally interactive, consider using `tabindex="-1"` to make it focusable only when it is actually interactive.',
|
|
451
453
|
message: (element) => `${element.localName} elements should not have \`tabindex\` attribute`,
|
|
452
454
|
selector: "[tabindex]",
|
|
453
455
|
match(element) {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
type DynamicString = string | ((element: Element) => string);
|
|
2
|
+
export interface AuditRule {
|
|
3
|
+
code: string;
|
|
4
|
+
title: DynamicString;
|
|
5
|
+
message: DynamicString;
|
|
6
|
+
description?: DynamicString;
|
|
7
|
+
}
|
|
8
|
+
export interface ResolvedAuditRule {
|
|
9
|
+
code: string;
|
|
10
|
+
title: string;
|
|
11
|
+
message: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface AuditRuleWithSelector extends AuditRule {
|
|
15
|
+
selector: string;
|
|
16
|
+
match?: (element: Element) => boolean | null | undefined | void | Promise<boolean> | Promise<void> | Promise<null> | Promise<undefined>;
|
|
17
|
+
}
|
|
18
|
+
export declare const rulesCategories: ({
|
|
19
|
+
code: string;
|
|
20
|
+
name: string;
|
|
21
|
+
icon: "person-arms-spread";
|
|
22
|
+
rules: AuditRuleWithSelector[];
|
|
23
|
+
} | {
|
|
24
|
+
code: string;
|
|
25
|
+
name: string;
|
|
26
|
+
icon: "gauge";
|
|
27
|
+
rules: AuditRuleWithSelector[];
|
|
28
|
+
})[];
|
|
29
|
+
export declare function resolveAuditRule(rule: AuditRule, element: Element): ResolvedAuditRule;
|
|
30
|
+
export declare function getAuditCategory(rule: AuditRule): 'perf' | 'a11y';
|
|
31
|
+
export declare const categoryLabel: {
|
|
32
|
+
perf: string;
|
|
33
|
+
a11y: string;
|
|
34
|
+
};
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { settings } from "../../../settings.js";
|
|
2
|
+
import { a11y } from "./a11y.js";
|
|
3
|
+
import { perf } from "./perf.js";
|
|
4
|
+
const rulesCategories = [
|
|
5
|
+
{ code: "a11y", name: "Accessibility", icon: "person-arms-spread", rules: a11y },
|
|
6
|
+
{ code: "perf", name: "Performance", icon: "gauge", rules: perf }
|
|
7
|
+
];
|
|
8
|
+
const dynamicAuditRuleKeys = ["title", "message", "description"];
|
|
9
|
+
function resolveAuditRule(rule, element) {
|
|
10
|
+
let resolved = { ...rule };
|
|
11
|
+
for (const key of dynamicAuditRuleKeys) {
|
|
12
|
+
const value = rule[key];
|
|
13
|
+
if (typeof value === "string")
|
|
14
|
+
continue;
|
|
15
|
+
try {
|
|
16
|
+
if (!value) {
|
|
17
|
+
resolved[key] = "";
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
resolved[key] = value(element);
|
|
21
|
+
} catch (err) {
|
|
22
|
+
settings.logger.error(`Error resolving dynamic audit rule ${rule.code}'s ${key}: ${err}`);
|
|
23
|
+
resolved[key] = "Error resolving dynamic rule";
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return resolved;
|
|
27
|
+
}
|
|
28
|
+
function getAuditCategory(rule) {
|
|
29
|
+
return rule.code.split("-")[0];
|
|
30
|
+
}
|
|
31
|
+
const categoryLabel = {
|
|
32
|
+
perf: "performance",
|
|
33
|
+
a11y: "accessibility"
|
|
34
|
+
};
|
|
35
|
+
export {
|
|
36
|
+
categoryLabel,
|
|
37
|
+
getAuditCategory,
|
|
38
|
+
resolveAuditRule,
|
|
39
|
+
rulesCategories
|
|
40
|
+
};
|
|
@@ -21,7 +21,7 @@ const perf = [
|
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
code: "perf-use-loading-lazy",
|
|
24
|
-
title:
|
|
24
|
+
title: "Unoptimized loading attribute",
|
|
25
25
|
message: (element) => `This ${element.nodeName} tag is below the fold and could be lazy-loaded to improve performance.`,
|
|
26
26
|
selector: 'img:not([loading]), img[loading="eager"], iframe:not([loading]), iframe[loading="eager"]',
|
|
27
27
|
match(element) {
|
|
@@ -35,7 +35,7 @@ const perf = [
|
|
|
35
35
|
},
|
|
36
36
|
{
|
|
37
37
|
code: "perf-use-loading-eager",
|
|
38
|
-
title:
|
|
38
|
+
title: "Unoptimized loading attribute",
|
|
39
39
|
message: (element) => `This ${element.nodeName} tag is above the fold and could be eagerly-loaded to improve performance.`,
|
|
40
40
|
selector: 'img[loading="lazy"], iframe[loading="lazy"]',
|
|
41
41
|
match(element) {
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
class DevToolbarAuditListItem extends HTMLElement {
|
|
2
|
+
clickAction;
|
|
3
|
+
shadowRoot;
|
|
4
|
+
isManualFocus;
|
|
5
|
+
constructor() {
|
|
6
|
+
super();
|
|
7
|
+
this.shadowRoot = this.attachShadow({ mode: "open" });
|
|
8
|
+
this.isManualFocus = false;
|
|
9
|
+
this.shadowRoot.innerHTML = `
|
|
10
|
+
<style>
|
|
11
|
+
:host>button, :host>div {
|
|
12
|
+
box-sizing: border-box;
|
|
13
|
+
padding: 16px;
|
|
14
|
+
background: transparent;
|
|
15
|
+
border: none;
|
|
16
|
+
border-bottom: 1px solid #1F2433;
|
|
17
|
+
text-decoration: none;
|
|
18
|
+
width: 100%;
|
|
19
|
+
height: 100%;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
h1, h2, h3, h4, h5, h6 {
|
|
23
|
+
color: #fff;
|
|
24
|
+
font-weight: 600;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
:host>button:hover, :host([hovered])>button {
|
|
28
|
+
background: #FFFFFF20;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
svg {
|
|
32
|
+
display: block;
|
|
33
|
+
margin: 0 auto;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
:host>button#astro-overlay-card {
|
|
37
|
+
text-align: left;
|
|
38
|
+
box-shadow: none;
|
|
39
|
+
display: flex;
|
|
40
|
+
align-items: center;
|
|
41
|
+
overflow: hidden;
|
|
42
|
+
gap: 8px;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
:host(:not([active]))>button:hover {
|
|
46
|
+
cursor: pointer;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.extended-info {
|
|
50
|
+
display: none;
|
|
51
|
+
color: white;
|
|
52
|
+
font-size: 14px;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.extended-info hr {
|
|
56
|
+
border: 1px solid rgba(27, 30, 36, 1);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
:host([active]) .extended-info {
|
|
60
|
+
display: block;
|
|
61
|
+
position: absolute;
|
|
62
|
+
height: 100%;
|
|
63
|
+
top: 98px;
|
|
64
|
+
height: calc(100% - 98px);
|
|
65
|
+
background: #0d0e12;
|
|
66
|
+
user-select: text;
|
|
67
|
+
overflow: auto;
|
|
68
|
+
border: none;
|
|
69
|
+
z-index: 1000000000;
|
|
70
|
+
flex-direction: column;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
:host([active])>button#astro-overlay-card {
|
|
74
|
+
display: none;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.audit-title {
|
|
78
|
+
margin: 0;
|
|
79
|
+
margin-bottom: 4px;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.extended-info .audit-selector {
|
|
83
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
84
|
+
display: flex;
|
|
85
|
+
align-items: center;
|
|
86
|
+
border-bottom: 1px solid transparent;
|
|
87
|
+
user-select: none;
|
|
88
|
+
color: rgba(191, 193, 201, 1);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.extended-info .audit-selector:hover {
|
|
92
|
+
border-bottom: 1px solid rgba(255, 255, 255);
|
|
93
|
+
cursor: pointer;
|
|
94
|
+
color: #fff;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.audit-selector svg {
|
|
98
|
+
width: 16px;
|
|
99
|
+
height: 16px;
|
|
100
|
+
display: inline;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.extended-info .audit-description {
|
|
104
|
+
color: rgba(191, 193, 201, 1);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.reset-button {
|
|
108
|
+
text-align: left;
|
|
109
|
+
border: none;
|
|
110
|
+
margin: 0;
|
|
111
|
+
width: auto;
|
|
112
|
+
overflow: visible;
|
|
113
|
+
background: transparent;
|
|
114
|
+
font: inherit;
|
|
115
|
+
line-height: normal;
|
|
116
|
+
-webkit-font-smoothing: inherit;
|
|
117
|
+
-moz-osx-font-smoothing: inherit;
|
|
118
|
+
-webkit-appearance: none;
|
|
119
|
+
padding: 0;
|
|
120
|
+
color: white;
|
|
121
|
+
}
|
|
122
|
+
</style>
|
|
123
|
+
|
|
124
|
+
<button id="astro-overlay-card">
|
|
125
|
+
<slot />
|
|
126
|
+
</button>
|
|
127
|
+
`;
|
|
128
|
+
}
|
|
129
|
+
connectedCallback() {
|
|
130
|
+
if (this.clickAction) {
|
|
131
|
+
this.shadowRoot.getElementById("astro-overlay-card")?.addEventListener("click", this.clickAction);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
export {
|
|
136
|
+
DevToolbarAuditListItem
|
|
137
|
+
};
|