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.
Files changed (98) hide show
  1. package/components/Code.astro +15 -12
  2. package/dist/@types/astro.d.ts +95 -18
  3. package/dist/assets/utils/getAssetsPrefix.d.ts +2 -0
  4. package/dist/assets/utils/getAssetsPrefix.js +14 -0
  5. package/dist/assets/vite-plugin-assets.js +10 -3
  6. package/dist/cli/add/index.js +76 -28
  7. package/dist/cli/install-package.js +2 -2
  8. package/dist/content/types-generator.js +56 -7
  9. package/dist/content/vite-plugin-content-assets.js +11 -3
  10. package/dist/core/app/common.js +2 -0
  11. package/dist/core/app/index.js +10 -2
  12. package/dist/core/app/types.d.ts +7 -2
  13. package/dist/core/base-pipeline.d.ts +2 -1
  14. package/dist/core/base-pipeline.js +2 -1
  15. package/dist/core/build/generate.js +1 -0
  16. package/dist/core/build/internal.d.ts +6 -0
  17. package/dist/core/build/internal.js +1 -0
  18. package/dist/core/build/plugins/index.js +6 -1
  19. package/dist/core/build/plugins/plugin-analyzer.js +10 -98
  20. package/dist/core/build/plugins/plugin-css.js +27 -1
  21. package/dist/core/build/plugins/plugin-manifest.js +5 -2
  22. package/dist/core/build/plugins/plugin-scripts.d.ts +8 -0
  23. package/dist/core/build/plugins/plugin-scripts.js +34 -0
  24. package/dist/core/compile/compile.d.ts +1 -7
  25. package/dist/core/compile/compile.js +5 -4
  26. package/dist/core/compile/style.d.ts +4 -3
  27. package/dist/core/compile/style.js +5 -4
  28. package/dist/core/compile/types.d.ts +11 -0
  29. package/dist/core/config/schema.d.ts +177 -113
  30. package/dist/core/config/schema.js +42 -9
  31. package/dist/core/config/vite-load.js +1 -0
  32. package/dist/core/constants.d.ts +1 -0
  33. package/dist/core/constants.js +3 -1
  34. package/dist/core/create-vite.js +5 -3
  35. package/dist/core/dev/dev.js +1 -1
  36. package/dist/core/errors/dev/vite.js +1 -1
  37. package/dist/core/messages.js +2 -2
  38. package/dist/core/render/params-and-props.js +2 -1
  39. package/dist/core/render/ssr-element.d.ts +8 -8
  40. package/dist/core/render/ssr-element.js +4 -2
  41. package/dist/core/render-context.js +3 -1
  42. package/dist/core/routing/astro-designed-error-pages.d.ts +2 -0
  43. package/dist/core/routing/astro-designed-error-pages.js +21 -0
  44. package/dist/runtime/client/dev-toolbar/apps/audit/index.d.ts +8 -15
  45. package/dist/runtime/client/dev-toolbar/apps/audit/index.js +130 -249
  46. package/dist/runtime/client/dev-toolbar/apps/audit/{a11y.js → rules/a11y.js} +4 -2
  47. package/dist/runtime/client/dev-toolbar/apps/audit/rules/index.d.ts +35 -0
  48. package/dist/runtime/client/dev-toolbar/apps/audit/rules/index.js +40 -0
  49. package/dist/runtime/client/dev-toolbar/apps/audit/{perf.js → rules/perf.js} +2 -2
  50. package/dist/runtime/client/dev-toolbar/apps/audit/ui/audit-list-item.d.ts +7 -0
  51. package/dist/runtime/client/dev-toolbar/apps/audit/ui/audit-list-item.js +137 -0
  52. package/dist/runtime/client/dev-toolbar/apps/audit/ui/audit-list-window.d.ts +23 -0
  53. package/dist/runtime/client/dev-toolbar/apps/audit/ui/audit-list-window.js +384 -0
  54. package/dist/runtime/client/dev-toolbar/apps/audit/ui/audit-ui.d.ts +6 -0
  55. package/dist/runtime/client/dev-toolbar/apps/audit/ui/audit-ui.js +126 -0
  56. package/dist/runtime/client/dev-toolbar/apps/utils/window.d.ts +1 -1
  57. package/dist/runtime/client/dev-toolbar/apps/utils/window.js +3 -1
  58. package/dist/runtime/client/dev-toolbar/entrypoint.js +43 -15
  59. package/dist/runtime/client/dev-toolbar/settings.d.ts +3 -1
  60. package/dist/runtime/client/dev-toolbar/settings.js +8 -2
  61. package/dist/runtime/client/dev-toolbar/toolbar.d.ts +1 -0
  62. package/dist/runtime/client/dev-toolbar/toolbar.js +10 -8
  63. package/dist/runtime/client/dev-toolbar/ui-library/badge.d.ts +14 -4
  64. package/dist/runtime/client/dev-toolbar/ui-library/badge.js +72 -33
  65. package/dist/runtime/client/dev-toolbar/ui-library/button.d.ts +14 -4
  66. package/dist/runtime/client/dev-toolbar/ui-library/button.js +100 -47
  67. package/dist/runtime/client/dev-toolbar/ui-library/card.d.ts +9 -0
  68. package/dist/runtime/client/dev-toolbar/ui-library/card.js +57 -2
  69. package/dist/runtime/client/dev-toolbar/ui-library/highlight.d.ts +9 -0
  70. package/dist/runtime/client/dev-toolbar/ui-library/highlight.js +54 -2
  71. package/dist/runtime/client/dev-toolbar/ui-library/icons.d.ts +4 -0
  72. package/dist/runtime/client/dev-toolbar/ui-library/icons.js +5 -1
  73. package/dist/runtime/client/dev-toolbar/ui-library/toggle.d.ts +9 -0
  74. package/dist/runtime/client/dev-toolbar/ui-library/toggle.js +64 -5
  75. package/dist/runtime/compiler/index.d.ts +1 -1
  76. package/dist/runtime/compiler/index.js +2 -0
  77. package/dist/runtime/server/hydration.js +3 -2
  78. package/dist/runtime/server/index.d.ts +1 -1
  79. package/dist/runtime/server/index.js +2 -0
  80. package/dist/runtime/server/render/astro/factory.d.ts +1 -1
  81. package/dist/runtime/server/render/component.js +4 -5
  82. package/dist/runtime/server/render/index.d.ts +1 -0
  83. package/dist/runtime/server/render/index.js +2 -0
  84. package/dist/runtime/server/render/script.d.ts +6 -0
  85. package/dist/runtime/server/render/script.js +15 -0
  86. package/dist/transitions/router.js +12 -3
  87. package/dist/vite-plugin-astro/index.d.ts +2 -2
  88. package/dist/vite-plugin-astro/index.js +12 -1
  89. package/dist/vite-plugin-astro/types.d.ts +21 -1
  90. package/dist/vite-plugin-astro-server/pipeline.js +6 -2
  91. package/dist/vite-plugin-astro-server/plugin.js +6 -2
  92. package/dist/vite-plugin-astro-server/response.d.ts +6 -0
  93. package/dist/vite-plugin-astro-server/response.js +13 -0
  94. package/dist/vite-plugin-astro-server/route.js +18 -2
  95. package/package.json +8 -9
  96. package/tsconfigs/base.json +3 -1
  97. /package/dist/runtime/client/dev-toolbar/apps/audit/{a11y.d.ts → rules/a11y.d.ts} +0 -0
  98. /package/dist/runtime/client/dev-toolbar/apps/audit/{perf.d.ts → rules/perf.d.ts} +0 -0
@@ -0,0 +1,23 @@
1
+ import type { Icon } from '../../../ui-library/icons.js';
2
+ import type { Audit } from '../index.js';
3
+ export declare function createRoundedBadge(icon: Icon): {
4
+ badge: import("../../../ui-library/badge.js").DevToolbarBadge;
5
+ updateCount: (count: number) => void;
6
+ };
7
+ export declare class DevToolbarAuditListWindow extends HTMLElement {
8
+ _audits: Audit[];
9
+ shadowRoot: ShadowRoot;
10
+ badges: {
11
+ [key: string]: {
12
+ badge: HTMLElement;
13
+ updateCount: (count: number) => void;
14
+ };
15
+ };
16
+ get audits(): Audit[];
17
+ set audits(value: Audit[]);
18
+ constructor();
19
+ connectedCallback(): void;
20
+ updateAuditList(): void;
21
+ updateBadgeCounts(): void;
22
+ render(): void;
23
+ }
@@ -0,0 +1,384 @@
1
+ import { getAuditCategory, rulesCategories } from "../rules/index.js";
2
+ function createRoundedBadge(icon) {
3
+ const badge = document.createElement("astro-dev-toolbar-badge");
4
+ badge.shadowRoot.innerHTML += `
5
+ <style>
6
+ :host>div {
7
+ padding: 12px 8px;
8
+ font-size: 14px;
9
+ display: flex;
10
+ gap: 4px;
11
+ }
12
+ </style>
13
+ `;
14
+ badge.innerHTML = `<astro-dev-toolbar-icon icon="${icon}"></astro-dev-toolbar-icon>0`;
15
+ return {
16
+ badge,
17
+ updateCount: (count) => {
18
+ if (count === 0) {
19
+ badge.badgeStyle = "green";
20
+ } else {
21
+ badge.badgeStyle = "purple";
22
+ }
23
+ badge.innerHTML = `<astro-dev-toolbar-icon icon="${icon}"></astro-dev-toolbar-icon>${count}`;
24
+ }
25
+ };
26
+ }
27
+ class DevToolbarAuditListWindow extends HTMLElement {
28
+ _audits = [];
29
+ shadowRoot;
30
+ badges = {};
31
+ get audits() {
32
+ return this._audits;
33
+ }
34
+ set audits(value) {
35
+ this._audits = value;
36
+ this.render();
37
+ }
38
+ constructor() {
39
+ super();
40
+ this.shadowRoot = this.attachShadow({ mode: "open" });
41
+ this.shadowRoot.innerHTML = `<style>
42
+ :host {
43
+ box-sizing: border-box;
44
+ display: flex;
45
+ flex-direction: column;
46
+ background: linear-gradient(0deg, #13151a, #13151a), linear-gradient(0deg, #343841, #343841);
47
+ border: 1px solid rgba(52, 56, 65, 1);
48
+ width: min(640px, 100%);
49
+ max-height: 480px;
50
+ border-radius: 12px;
51
+ padding: 24px;
52
+ font-family:
53
+ ui-sans-serif,
54
+ system-ui,
55
+ -apple-system,
56
+ BlinkMacSystemFont,
57
+ "Segoe UI",
58
+ Roboto,
59
+ "Helvetica Neue",
60
+ Arial,
61
+ "Noto Sans",
62
+ sans-serif,
63
+ "Apple Color Emoji",
64
+ "Segoe UI Emoji",
65
+ "Segoe UI Symbol",
66
+ "Noto Color Emoji";
67
+ color: rgba(191, 193, 201, 1);
68
+ position: fixed;
69
+ z-index: 999999999;
70
+ bottom: 72px;
71
+ left: 50%;
72
+ transform: translateX(-50%);
73
+ box-shadow:
74
+ 0px 0px 0px 0px rgba(19, 21, 26, 0.3),
75
+ 0px 1px 2px 0px rgba(19, 21, 26, 0.29),
76
+ 0px 4px 4px 0px rgba(19, 21, 26, 0.26),
77
+ 0px 10px 6px 0px rgba(19, 21, 26, 0.15),
78
+ 0px 17px 7px 0px rgba(19, 21, 26, 0.04),
79
+ 0px 26px 7px 0px rgba(19, 21, 26, 0.01);
80
+ }
81
+
82
+ @media (forced-colors: active) {
83
+ :host {
84
+ background: white;
85
+ }
86
+ }
87
+
88
+ @media (max-width: 640px) {
89
+ :host {
90
+ border-radius: 0;
91
+ }
92
+ }
93
+
94
+ hr,
95
+ ::slotted(hr) {
96
+ border: 1px solid rgba(27, 30, 36, 1);
97
+ margin: 1em 0;
98
+ }
99
+
100
+ .reset-button {
101
+ text-align: left;
102
+ border: none;
103
+ margin: 0;
104
+ width: auto;
105
+ overflow: visible;
106
+ background: transparent;
107
+ font: inherit;
108
+ line-height: normal;
109
+ -webkit-font-smoothing: inherit;
110
+ -moz-osx-font-smoothing: inherit;
111
+ -webkit-appearance: none;
112
+ padding: 0;
113
+ }
114
+
115
+ :host {
116
+ left: initial;
117
+ top: 8px;
118
+ right: 8px;
119
+ transform: none;
120
+ width: 350px;
121
+ min-height: 350px;
122
+ max-height: 420px;
123
+ padding: 0;
124
+ overflow: hidden;
125
+ }
126
+
127
+ hr {
128
+ margin: 0;
129
+ }
130
+
131
+ header {
132
+ display: flex;
133
+ align-items: center;
134
+ gap: 4px;
135
+ }
136
+
137
+ header > section {
138
+ display: flex;
139
+ align-items: center;
140
+ gap: 1em;
141
+ padding: 18px;
142
+ }
143
+
144
+ header.category-header {
145
+ background: rgba(27, 30, 36, 1);
146
+ padding: 10px 16px;
147
+ position: sticky;
148
+ top: 0;
149
+ }
150
+
151
+ header.category-header astro-dev-toolbar-icon {
152
+ opacity: 0.6;
153
+ }
154
+
155
+ #audit-counts {
156
+ display: flex;
157
+ gap: 0.5em;
158
+ }
159
+
160
+ #audit-counts > div {
161
+ display: flex;
162
+ gap: 8px;
163
+ align-items: center;
164
+ }
165
+
166
+ ul,
167
+ li {
168
+ margin: 0;
169
+ padding: 0;
170
+ list-style: none;
171
+ }
172
+
173
+ h1 {
174
+ font-size: 24px;
175
+ font-weight: 600;
176
+ color: #fff;
177
+ margin: 0;
178
+ }
179
+
180
+ h2 {
181
+ font-weight: 600;
182
+ margin: 0;
183
+ color: white;
184
+ font-size: 14px;
185
+ }
186
+
187
+ h3 {
188
+ font-weight: normal;
189
+ margin: 0;
190
+ color: white;
191
+ font-size: 14px;
192
+ }
193
+
194
+ .audit-header {
195
+ display: flex;
196
+ gap: 8px;
197
+ align-items: center;
198
+ }
199
+
200
+ .audit-selector {
201
+ color: white;
202
+ font-size: 12px;
203
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
204
+ "Liberation Mono", "Courier New", monospace;
205
+ border: 1px solid rgba(255, 255, 255, 0.1);
206
+ border-radius: 4px;
207
+ padding: 4px 6px;
208
+ }
209
+
210
+ [active] .audit-selector:hover {
211
+ text-decoration: underline;
212
+ cursor: pointer;
213
+ }
214
+
215
+ .selector-title-container {
216
+ display: flex;
217
+ align-items: center;
218
+ gap: 8px;
219
+ }
220
+
221
+ astro-dev-toolbar-icon {
222
+ color: white;
223
+ fill: white;
224
+ display: inline-block;
225
+ height: 16px;
226
+ width: 16px;
227
+ }
228
+
229
+ #audit-list {
230
+ display: flex;
231
+ flex-direction: column;
232
+ overflow: auto;
233
+ overscroll-behavior: contain;
234
+ height: 100%;
235
+ }
236
+
237
+ #back-to-list {
238
+ display: none;
239
+ align-items: center;
240
+ justify-content: center;
241
+ background: rgba(27, 30, 36, 1);
242
+ gap: 8px;
243
+ padding: 8px;
244
+ color: white;
245
+ font-size: 14px;
246
+ padding-right: 24px;
247
+ }
248
+
249
+ #back-to-list:hover {
250
+ cursor: pointer;
251
+ background: #313236;
252
+ }
253
+
254
+ #back-to-list:has(+ #audit-list astro-dev-toolbar-audit-list-item[active]) {
255
+ display: flex;
256
+ }
257
+
258
+ .no-audit-container {
259
+ display: flex;
260
+ flex-direction: column;
261
+ padding: 24px;
262
+ }
263
+
264
+ .no-audit-container h1 {
265
+ font-size: 20px;
266
+ }
267
+
268
+ .no-audit-container astro-dev-toolbar-icon {
269
+ width: auto;
270
+ height: auto;
271
+ margin: 0 auto;
272
+ }
273
+ </style>
274
+
275
+ <template id="category-template">
276
+ <div>
277
+ <header class="category-header">
278
+ </header>
279
+ <div class="category-content"></div>
280
+ </div>
281
+ </template>
282
+
283
+ <header>
284
+ <section id="header-left">
285
+ <h1>Audit</h1>
286
+ <section id="audit-counts"></section>
287
+ </section>
288
+ </header>
289
+ <hr />
290
+ <button id="back-to-list" class="reset-button">
291
+ <astro-dev-toolbar-icon icon="arrow-left"></astro-dev-toolbar-icon>
292
+ Back to list
293
+ </button>
294
+ <div id="audit-list"></div>
295
+ `;
296
+ const auditCounts = this.shadowRoot.getElementById("audit-counts");
297
+ if (auditCounts) {
298
+ rulesCategories.forEach((category) => {
299
+ const headerEntryContainer = document.createElement("div");
300
+ const auditCount = this.audits.filter(
301
+ (audit) => getAuditCategory(audit.rule) === category.code
302
+ ).length;
303
+ const categoryBadge = createRoundedBadge(category.icon);
304
+ categoryBadge.updateCount(auditCount);
305
+ headerEntryContainer.append(categoryBadge.badge);
306
+ auditCounts.append(headerEntryContainer);
307
+ this.badges[category.code] = categoryBadge;
308
+ });
309
+ }
310
+ const backToListButton = this.shadowRoot.getElementById("back-to-list");
311
+ if (backToListButton) {
312
+ backToListButton.addEventListener("click", () => {
313
+ const activeAudit = this.shadowRoot.querySelector(
314
+ "astro-dev-toolbar-audit-list-item[active]"
315
+ );
316
+ if (activeAudit) {
317
+ activeAudit.toggleAttribute("active", false);
318
+ }
319
+ });
320
+ }
321
+ }
322
+ connectedCallback() {
323
+ this.render();
324
+ }
325
+ updateAuditList() {
326
+ const auditListContainer = this.shadowRoot.getElementById("audit-list");
327
+ if (auditListContainer) {
328
+ auditListContainer.innerHTML = "";
329
+ if (this.audits.length > 0) {
330
+ for (const category of rulesCategories) {
331
+ const template = this.shadowRoot.getElementById(
332
+ "category-template"
333
+ );
334
+ if (!template)
335
+ return;
336
+ const clone = document.importNode(template.content, true);
337
+ const categoryContainer = clone.querySelector("div");
338
+ const categoryHeader = clone.querySelector(".category-header");
339
+ categoryHeader.innerHTML = `<astro-dev-toolbar-icon icon="${category.icon}"></astro-dev-toolbar-icon><h2>${category.name}</h2>`;
340
+ categoryContainer.append(categoryHeader);
341
+ const categoryContent = clone.querySelector(".category-content");
342
+ const categoryAudits = this.audits.filter(
343
+ (audit) => getAuditCategory(audit.rule) === category.code
344
+ );
345
+ for (const audit of categoryAudits) {
346
+ if (audit.card)
347
+ categoryContent.append(audit.card);
348
+ }
349
+ categoryContainer.append(categoryContent);
350
+ auditListContainer.append(categoryContainer);
351
+ }
352
+ } else {
353
+ const noAuditContainer = document.createElement("div");
354
+ noAuditContainer.classList.add("no-audit-container");
355
+ noAuditContainer.innerHTML = `
356
+ <header>
357
+ <h1></astro-dev-toolbar-icon>No accessibility or performance issues detected.</h1>
358
+ </header>
359
+ <p>
360
+ 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.
361
+ </p>
362
+ <astro-dev-toolbar-icon icon="houston-detective"></astro-dev-toolbar-icon>
363
+ `;
364
+ auditListContainer.append(noAuditContainer);
365
+ }
366
+ }
367
+ }
368
+ updateBadgeCounts() {
369
+ for (const category of rulesCategories) {
370
+ const auditCount = this.audits.filter(
371
+ (audit) => getAuditCategory(audit.rule) === category.code
372
+ ).length;
373
+ this.badges[category.code].updateCount(auditCount);
374
+ }
375
+ }
376
+ render() {
377
+ this.updateAuditList();
378
+ this.updateBadgeCounts();
379
+ }
380
+ }
381
+ export {
382
+ DevToolbarAuditListWindow,
383
+ createRoundedBadge
384
+ };
@@ -0,0 +1,6 @@
1
+ import type { Audit } from '../index.js';
2
+ import type { DevToolbarAuditListItem } from './audit-list-item.js';
3
+ export declare function createAuditUI(audit: Audit, audits: Audit[]): {
4
+ highlight: import("../../../ui-library/highlight.js").DevToolbarHighlight;
5
+ card: DevToolbarAuditListItem;
6
+ };
@@ -0,0 +1,126 @@
1
+ import { escape as escapeHTML } from "html-escaper";
2
+ import {
3
+ attachTooltipToHighlight,
4
+ createHighlight,
5
+ getElementsPositionInDocument
6
+ } from "../../utils/highlight.js";
7
+ import { resolveAuditRule } from "../rules/index.js";
8
+ function truncate(val, maxLength) {
9
+ return val.length > maxLength ? val.slice(0, maxLength - 1) + "&hellip;" : val;
10
+ }
11
+ function createAuditUI(audit, audits) {
12
+ const rect = audit.auditedElement.getBoundingClientRect();
13
+ const highlight = createHighlight(rect, "warning", { "data-audit-code": audit.rule.code });
14
+ const resolvedAuditRule = resolveAuditRule(audit.rule, audit.auditedElement);
15
+ const tooltip = buildAuditTooltip(resolvedAuditRule, audit.auditedElement);
16
+ const card = buildAuditCard(resolvedAuditRule, highlight, audit.auditedElement, audits);
17
+ ["focus", "mouseover"].forEach((event) => {
18
+ const attribute = event === "focus" ? "active" : "hovered";
19
+ highlight.addEventListener(event, () => {
20
+ if (event === "focus") {
21
+ audits.forEach((adt) => {
22
+ if (adt.card)
23
+ adt.card.toggleAttribute("active", false);
24
+ });
25
+ if (!card.isManualFocus)
26
+ card.scrollIntoView();
27
+ card.toggleAttribute("active", true);
28
+ } else {
29
+ card.toggleAttribute(attribute, true);
30
+ }
31
+ });
32
+ });
33
+ highlight.addEventListener("mouseout", () => {
34
+ card.toggleAttribute("hovered", false);
35
+ });
36
+ const { isFixed } = getElementsPositionInDocument(audit.auditedElement);
37
+ if (isFixed) {
38
+ tooltip.style.position = highlight.style.position = "fixed";
39
+ }
40
+ attachTooltipToHighlight(highlight, tooltip, audit.auditedElement);
41
+ return { highlight, card };
42
+ }
43
+ function buildAuditTooltip(rule, element) {
44
+ const tooltip = document.createElement("astro-dev-toolbar-tooltip");
45
+ const { title, message } = rule;
46
+ tooltip.sections = [
47
+ {
48
+ icon: "warning",
49
+ title: escapeHTML(title)
50
+ },
51
+ {
52
+ content: escapeHTML(message)
53
+ }
54
+ ];
55
+ const elementFile = element.getAttribute("data-astro-source-file");
56
+ const elementPosition = element.getAttribute("data-astro-source-loc");
57
+ if (elementFile) {
58
+ const elementFileWithPosition = elementFile + (elementPosition ? ":" + elementPosition : "");
59
+ tooltip.sections.push({
60
+ content: elementFileWithPosition.slice(
61
+ window.__astro_dev_toolbar__.root.length - 1
62
+ // We want to keep the final slash, so minus one.
63
+ ),
64
+ clickDescription: "Click to go to file",
65
+ async clickAction() {
66
+ await fetch("/__open-in-editor?file=" + encodeURIComponent(elementFileWithPosition));
67
+ }
68
+ });
69
+ }
70
+ return tooltip;
71
+ }
72
+ function buildAuditCard(rule, highlightElement, auditedElement, audits) {
73
+ const card = document.createElement(
74
+ "astro-dev-toolbar-audit-list-item"
75
+ );
76
+ card.clickAction = () => {
77
+ if (card.hasAttribute("active"))
78
+ return;
79
+ audits.forEach((audit) => {
80
+ audit.card?.toggleAttribute("active", false);
81
+ });
82
+ highlightElement.scrollIntoView();
83
+ card.isManualFocus = true;
84
+ highlightElement.focus();
85
+ card.isManualFocus = false;
86
+ };
87
+ const selectorTitleContainer = document.createElement("section");
88
+ selectorTitleContainer.classList.add("selector-title-container");
89
+ const selector = document.createElement("span");
90
+ const selectorName = truncate(auditedElement.tagName.toLowerCase(), 8);
91
+ selector.classList.add("audit-selector");
92
+ selector.innerHTML = escapeHTML(selectorName);
93
+ const title = document.createElement("h3");
94
+ title.classList.add("audit-title");
95
+ title.innerText = rule.title;
96
+ selectorTitleContainer.append(selector, title);
97
+ card.append(selectorTitleContainer);
98
+ const extendedInfo = document.createElement("div");
99
+ extendedInfo.classList.add("extended-info");
100
+ const selectorButton = document.createElement("button");
101
+ selectorButton.className = "audit-selector reset-button";
102
+ selectorButton.innerHTML = `${selectorName} <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentColor" viewBox="0 0 256 256"><path d="M128,136v64a8,8,0,0,1-16,0V155.32L45.66,221.66a8,8,0,0,1-11.32-11.32L100.68,144H56a8,8,0,0,1,0-16h64A8,8,0,0,1,128,136ZM208,32H80A16,16,0,0,0,64,48V96a8,8,0,0,0,16,0V48H208V176H160a8,8,0,0,0,0,16h48a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32Z"></path></svg>`;
103
+ selectorButton.addEventListener("click", () => {
104
+ highlightElement.scrollIntoView();
105
+ highlightElement.focus();
106
+ });
107
+ extendedInfo.append(title.cloneNode(true));
108
+ extendedInfo.append(selectorButton);
109
+ extendedInfo.append(document.createElement("hr"));
110
+ const message = document.createElement("p");
111
+ message.classList.add("audit-message");
112
+ message.innerHTML = rule.message;
113
+ extendedInfo.appendChild(message);
114
+ const description = rule.description;
115
+ if (description) {
116
+ const descriptionElement = document.createElement("p");
117
+ descriptionElement.classList.add("audit-description");
118
+ descriptionElement.innerHTML = description;
119
+ extendedInfo.appendChild(descriptionElement);
120
+ }
121
+ card.shadowRoot.appendChild(extendedInfo);
122
+ return card;
123
+ }
124
+ export {
125
+ createAuditUI
126
+ };
@@ -1,2 +1,2 @@
1
1
  export declare function createWindowElement(content: string): import("../../ui-library/window.js").DevToolbarWindow;
2
- export declare function closeOnOutsideClick(eventTarget: EventTarget): void;
2
+ export declare function closeOnOutsideClick(eventTarget: EventTarget, additionalCheck?: (target: Element) => boolean): void;
@@ -3,7 +3,7 @@ function createWindowElement(content) {
3
3
  windowElement.innerHTML = content;
4
4
  return windowElement;
5
5
  }
6
- function closeOnOutsideClick(eventTarget) {
6
+ function closeOnOutsideClick(eventTarget, additionalCheck) {
7
7
  function onPageClick(event) {
8
8
  const target = event.target;
9
9
  if (!target)
@@ -12,6 +12,8 @@ function closeOnOutsideClick(eventTarget) {
12
12
  return;
13
13
  if (target.closest("astro-dev-toolbar"))
14
14
  return;
15
+ if (additionalCheck && additionalCheck(target))
16
+ return;
15
17
  eventTarget.dispatchEvent(
16
18
  new CustomEvent("toggle-app", {
17
19
  detail: {
@@ -51,6 +51,12 @@ document.addEventListener("DOMContentLoaded", async () => {
51
51
  customElements.define("astro-dev-overlay-badge", deprecated(DevToolbarBadge));
52
52
  customElements.define("astro-dev-overlay-icon", deprecated(DevToolbarIcon));
53
53
  overlay = document.createElement("astro-dev-toolbar");
54
+ const notificationLevels = ["error", "warning", "info"];
55
+ const notificationSVGs = {
56
+ error: '<svg viewBox="0 0 10 10"><rect width="9" height="9" x=".5" y=".5" fill="#B33E66" stroke="#13151A" rx="4.5"/></svg>',
57
+ warning: '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="10" fill="none"><path fill="#B58A2D" stroke="#13151A" d="M7.29904 1.25c-.57735-1-2.02073-1-2.59808 0l-3.4641 6C.65951 8.25 1.3812 9.5 2.5359 9.5h6.9282c1.1547 0 1.8764-1.25 1.299-2.25l-3.46406-6Z"/></svg>',
58
+ info: '<svg viewBox="0 0 10 10"><rect width="9" height="9" x=".5" y=".5" fill="#3645D9" stroke="#13151A" rx="1.5"/></svg>'
59
+ };
54
60
  const prepareApp = (appDefinition, builtIn) => {
55
61
  const eventTarget = new EventTarget();
56
62
  const app = {
@@ -58,19 +64,26 @@ document.addEventListener("DOMContentLoaded", async () => {
58
64
  builtIn,
59
65
  active: false,
60
66
  status: "loading",
61
- notification: { state: false },
67
+ notification: { state: false, level: void 0 },
62
68
  eventTarget
63
69
  };
64
70
  eventTarget.addEventListener("toggle-notification", (evt) => {
71
+ if (!(evt instanceof CustomEvent))
72
+ return;
65
73
  const target = overlay.shadowRoot?.querySelector(`[data-app-id="${app.id}"]`);
66
- if (!target)
74
+ const notificationElement = target?.querySelector(".notification");
75
+ if (!target || !notificationElement)
67
76
  return;
68
- let newState = true;
69
- if (evt instanceof CustomEvent) {
70
- newState = evt.detail.state ?? true;
71
- }
77
+ let newState = evt.detail.state ?? true;
78
+ let level = notificationLevels.includes(evt?.detail?.level) ? evt.detail.level : "error";
72
79
  app.notification.state = newState;
73
- target.querySelector(".notification")?.toggleAttribute("data-active", newState);
80
+ if (newState)
81
+ app.notification.level = level;
82
+ notificationElement.toggleAttribute("data-active", newState);
83
+ if (newState) {
84
+ notificationElement.setAttribute("data-level", level);
85
+ notificationElement.innerHTML = notificationSVGs[level];
86
+ }
74
87
  });
75
88
  const onToggleApp = async (evt) => {
76
89
  let newState = void 0;
@@ -112,12 +125,13 @@ document.addEventListener("DOMContentLoaded", async () => {
112
125
  display: none;
113
126
  position: absolute;
114
127
  top: -4px;
115
- right: -6px;
116
- width: 8px;
117
- height: 8px;
118
- border-radius: 9999px;
119
- border: 1px solid rgba(19, 21, 26, 1);
120
- background: #B33E66;
128
+ right: -5px;
129
+ width: 12px;
130
+ height: 10px;
131
+ }
132
+
133
+ .notification svg {
134
+ display: block;
121
135
  }
122
136
 
123
137
  #dropdown:not([data-no-notification]) .notification[data-active] {
@@ -189,11 +203,25 @@ document.addEventListener("DOMContentLoaded", async () => {
189
203
  app.eventTarget.addEventListener("toggle-notification", (evt) => {
190
204
  if (!(evt instanceof CustomEvent))
191
205
  return;
192
- notification.toggleAttribute("data-active", evt.detail.state ?? true);
206
+ let newState = evt.detail.state ?? true;
207
+ let level = notificationLevels.includes(evt?.detail?.level) ? evt.detail.level : "error";
208
+ notification.toggleAttribute("data-active", newState);
209
+ if (newState) {
210
+ notification.setAttribute("data-level", level);
211
+ notification.innerHTML = notificationSVGs[level];
212
+ }
213
+ app.notification.state = newState;
214
+ if (newState)
215
+ app.notification.level = level;
193
216
  eventTarget.dispatchEvent(
194
217
  new CustomEvent("toggle-notification", {
195
218
  detail: {
196
- state: hiddenApps.some((p) => p.notification.state === true)
219
+ state: hiddenApps.some((p) => p.notification.state === true),
220
+ level: ["error", "warning", "info"].find(
221
+ (notificationLevel) => hiddenApps.some(
222
+ (p) => p.notification.state === true && p.notification.level === notificationLevel
223
+ )
224
+ ) ?? "error"
197
225
  }
198
226
  })
199
227
  );
@@ -10,7 +10,9 @@ export declare const settings: {
10
10
  readonly config: Settings;
11
11
  updateSetting: (key: keyof Settings, value: boolean) => void;
12
12
  logger: {
13
- log: (message: string) => void;
13
+ log: (message: string, level?: 'log' | 'warn' | 'error') => void;
14
+ warn: (message: string) => void;
15
+ error: (message: string) => void;
14
16
  verboseLog: (message: string) => void;
15
17
  };
16
18
  };
@@ -18,8 +18,8 @@ function getSettings() {
18
18
  _settings[key] = value;
19
19
  localStorage.setItem("astro:dev-toolbar:settings", JSON.stringify(_settings));
20
20
  }
21
- function log(message) {
22
- console.log(
21
+ function log(message, level = "log") {
22
+ console[level](
23
23
  `%cAstro`,
24
24
  "background: linear-gradient(66.77deg, #D83333 0%, #F041FF 100%); color: white; padding-inline: 4px; border-radius: 2px; font-family: monospace;",
25
25
  message
@@ -32,6 +32,12 @@ function getSettings() {
32
32
  updateSetting,
33
33
  logger: {
34
34
  log,
35
+ warn: (message) => {
36
+ log(message, "warn");
37
+ },
38
+ error: (message) => {
39
+ log(message, "error");
40
+ },
35
41
  verboseLog: (message) => {
36
42
  if (_settings.verbose) {
37
43
  log(message);