browser-debugger-cli 0.10.0 → 0.12.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/.claude/skills/bdg/SKILL.md +268 -0
- package/README.md +148 -74
- package/dist/commands/css.d.ts +13 -0
- package/dist/commands/css.js +53 -0
- package/dist/commands/dom/audit.d.ts +14 -0
- package/dist/commands/dom/audit.js +87 -0
- package/dist/commands/dom/formInteraction.js +36 -6
- package/dist/commands/dom/helpers/keyAttributes.d.ts +3 -2
- package/dist/commands/dom/helpers/keyAttributes.js +6 -4
- package/dist/commands/dom/helpers/screenshot.d.ts +1 -0
- package/dist/commands/dom/helpers/screenshot.js +158 -38
- package/dist/commands/dom/index.js +4 -1
- package/dist/commands/dom/screenshot.js +10 -6
- package/dist/commands/dom/wait.js +5 -3
- package/dist/commands/helpJson.js +1 -1
- package/dist/commands/installSkill.d.ts +20 -0
- package/dist/commands/installSkill.js +87 -0
- package/dist/commands/optionBehaviors.js +21 -6
- package/dist/commands/page.js +7 -4
- package/dist/commands/peek.d.ts +7 -0
- package/dist/commands/peek.js +65 -23
- package/dist/commands/shared/optionTypes.d.ts +5 -1
- package/dist/commands/start.d.ts +13 -0
- package/dist/commands/start.js +19 -2
- package/dist/commands/tail.d.ts +7 -1
- package/dist/commands/tail.js +13 -62
- package/dist/commands.js +5 -0
- package/dist/daemon/session/commandRegistry.js +7 -1
- package/dist/daemon/session/plugins.js +4 -52
- package/dist/daemon.js +7986 -6848
- package/dist/errors/messages.d.ts +50 -4
- package/dist/errors/messages.js +94 -5
- package/dist/index.js +709 -190
- package/dist/ipc/client.d.ts +4 -0
- package/dist/ipc/client.js +8 -0
- package/dist/ipc/protocol/auditTypes.d.ts +129 -0
- package/dist/ipc/protocol/auditTypes.js +6 -0
- package/dist/ipc/protocol/commands.d.ts +23 -0
- package/dist/ipc/protocol/commands.js +2 -0
- package/dist/ipc/protocol/domTypes.d.ts +4 -0
- package/dist/ipc/protocol/inspectTypes.d.ts +71 -8
- package/dist/runtime/css/search.d.ts +39 -0
- package/dist/runtime/css/search.js +122 -0
- package/dist/runtime/dom/actionEffects.d.ts +4 -1
- package/dist/runtime/dom/actionEffects.js +8 -4
- package/dist/runtime/dom/audit.d.ts +19 -0
- package/dist/runtime/dom/audit.js +36 -0
- package/dist/runtime/dom/auditModel.d.ts +45 -0
- package/dist/runtime/dom/auditModel.js +215 -0
- package/dist/runtime/dom/auditScripts.d.ts +107 -0
- package/dist/runtime/dom/auditScripts.js +112 -0
- package/dist/runtime/dom/elementGeometry.d.ts +8 -2
- package/dist/runtime/dom/elementGeometry.js +24 -8
- package/dist/runtime/dom/elementInfo.d.ts +3 -2
- package/dist/runtime/dom/elementInfo.js +8 -2
- package/dist/runtime/dom/formFillHelpers/fill.js +2 -2
- package/dist/runtime/dom/inspect.d.ts +7 -0
- package/dist/runtime/dom/inspect.js +88 -23
- package/dist/runtime/dom/inspectAllStyles.d.ts +16 -4
- package/dist/runtime/dom/inspectAllStyles.js +89 -7
- package/dist/runtime/dom/inspectCascade.d.ts +19 -2
- package/dist/runtime/dom/inspectCascade.js +214 -44
- package/dist/runtime/dom/inspectCascadeModel.d.ts +8 -0
- package/dist/runtime/dom/inspectCascadeModel.js +108 -34
- package/dist/runtime/dom/inspectHints.d.ts +26 -3
- package/dist/runtime/dom/inspectHints.js +125 -9
- package/dist/runtime/dom/inspectModel.d.ts +3 -0
- package/dist/runtime/dom/inspectModel.js +30 -7
- package/dist/runtime/dom/inspectPaintModel.d.ts +48 -22
- package/dist/runtime/dom/inspectPaintModel.js +180 -68
- package/dist/runtime/dom/inspectRules.d.ts +19 -0
- package/dist/runtime/dom/inspectRules.js +21 -5
- package/dist/runtime/dom/inspectScripts.d.ts +85 -12
- package/dist/runtime/dom/inspectScripts.js +314 -28
- package/dist/runtime/dom/inspectTree.js +10 -2
- package/dist/runtime/dom/inspectWhyModel.d.ts +2 -1
- package/dist/runtime/dom/inspectWhyModel.js +52 -10
- package/dist/runtime/dom/layout.js +31 -9
- package/dist/runtime/dom/reactEventHelpers.d.ts +7 -0
- package/dist/runtime/dom/reactEventHelpers.js +27 -9
- package/dist/runtime/page/emulation.d.ts +13 -4
- package/dist/runtime/page/emulation.js +69 -4
- package/dist/runtime/page/userAgent.d.ts +17 -0
- package/dist/runtime/page/userAgent.js +57 -0
- package/dist/types.d.ts +12 -0
- package/dist/ui/formatters/audit.d.ts +19 -0
- package/dist/ui/formatters/audit.js +106 -0
- package/dist/ui/formatters/dom.d.ts +1 -1
- package/dist/ui/formatters/dom.js +6 -3
- package/dist/ui/formatters/inspect.js +42 -15
- package/dist/ui/formatters/installSkill.d.ts +11 -0
- package/dist/ui/formatters/installSkill.js +31 -0
- package/dist/ui/formatters/status.js +1 -1
- package/dist/ui/messages/commands.d.ts +44 -7
- package/dist/ui/messages/commands.js +83 -11
- package/dist/ui/messages/preview.d.ts +6 -0
- package/dist/ui/messages/preview.js +9 -1
- package/dist/utils/cssValues.js +36 -4
- package/dist/utils/decisionTrees.js +0 -5
- package/dist/utils/suggestions.d.ts +4 -2
- package/dist/utils/suggestions.js +7 -5
- package/dist/utils/taskMappings.js +1 -1
- package/package.json +4 -2
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* canvas).
|
|
9
9
|
*/
|
|
10
10
|
import { composite, contrastLevel, contrastRatio, hexColor, parseColor, toHex, } from '../../utils/color.js';
|
|
11
|
-
import { cssLength, firstFontFamily, normalizeCssValue, parseShadows, pxNumber, readableTransform, shadowText, shortUrls, splitTopLevel, } from '../../utils/cssValues.js';
|
|
11
|
+
import { cssLength, firstFontFamily, normalizeCssValue, parseShadows, pxNumber, readableTransform, shadowText, shortUrls, sidesShorthand, splitTopLevel, } from '../../utils/cssValues.js';
|
|
12
12
|
/** Background images and gradients are shown at most this long */
|
|
13
13
|
const IMAGE_TEXT_LENGTH = 140;
|
|
14
14
|
/** Page canvas colors (light and dark color-scheme) */
|
|
@@ -16,62 +16,125 @@ const CANVAS = {
|
|
|
16
16
|
light: { r: 1, g: 1, b: 1, a: 1 },
|
|
17
17
|
dark: { r: 0x12 / 255, g: 0x12 / 255, b: 0x12 / 255, a: 1 },
|
|
18
18
|
};
|
|
19
|
+
/** CSS generic font families: the browser picks a font for them */
|
|
20
|
+
const GENERIC_FAMILIES = new Set([
|
|
21
|
+
'serif',
|
|
22
|
+
'sans-serif',
|
|
23
|
+
'monospace',
|
|
24
|
+
'cursive',
|
|
25
|
+
'fantasy',
|
|
26
|
+
'system-ui',
|
|
27
|
+
'ui-serif',
|
|
28
|
+
'ui-sans-serif',
|
|
29
|
+
'ui-monospace',
|
|
30
|
+
'ui-rounded',
|
|
31
|
+
'math',
|
|
32
|
+
'emoji',
|
|
33
|
+
'fangsong',
|
|
34
|
+
'-apple-system',
|
|
35
|
+
'blinkmacsystemfont',
|
|
36
|
+
]);
|
|
19
37
|
/**
|
|
20
|
-
* The font the text was rendered with
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
38
|
+
* The font the text was rendered with and whether it is a web font. For a
|
|
39
|
+
* generic first family, the font it resolved to (`resolved`). Otherwise
|
|
40
|
+
* `rendered` only when it is a fallback: not a face of the first family
|
|
41
|
+
* (`DM Sans 9pt` is a face of `DM Sans`, `Liberation Sans` is not one of
|
|
42
|
+
* `Arial`), and the first family is not a web font the page loaded (whose
|
|
43
|
+
* file may give any internal name: `Copyright Klim Type Foundry`, or the
|
|
44
|
+
* local font a `src: local()` points at). Names that are not readable
|
|
45
|
+
* (sites that scramble a web font's internal name) are left out.
|
|
25
46
|
*
|
|
26
47
|
* @param family - First family of `font-family`
|
|
27
48
|
* @param fonts - Platform fonts of the text
|
|
28
|
-
* @
|
|
49
|
+
* @param familyLoaded - The first family is a loaded web font
|
|
50
|
+
* @returns `rendered`, `resolved` and `webfont` fields
|
|
29
51
|
*/
|
|
30
|
-
export function renderedFont(family, fonts) {
|
|
52
|
+
export function renderedFont(family, fonts, familyLoaded = false) {
|
|
31
53
|
const primary = [...fonts].sort((a, b) => b.glyphCount - a.glyphCount)[0];
|
|
32
54
|
if (!primary)
|
|
33
55
|
return {};
|
|
56
|
+
const webfont = primary.isCustomFont ? { webfont: true } : {};
|
|
34
57
|
const readable = /^[\p{L}\p{N}.][\p{L}\p{N} ._'-]+$/u.test(primary.familyName);
|
|
35
|
-
|
|
58
|
+
if (!readable || familyLoaded)
|
|
59
|
+
return webfont;
|
|
60
|
+
if (GENERIC_FAMILIES.has(family.toLowerCase())) {
|
|
61
|
+
return { resolved: primary.familyName, ...webfont };
|
|
62
|
+
}
|
|
63
|
+
const differs = !primary.familyName.toLowerCase().startsWith(family.toLowerCase());
|
|
64
|
+
return { ...(differs && { rendered: primary.familyName }), ...webfont };
|
|
65
|
+
}
|
|
66
|
+
/** Fully transparent */
|
|
67
|
+
const CLEAR = { r: 0, g: 0, b: 0, a: 0 };
|
|
68
|
+
/**
|
|
69
|
+
* Paint the text color and the background behind it the way the browser
|
|
70
|
+
* composites them: from the element up to the root, each element's content
|
|
71
|
+
* over its own background, the result faded by its opacity (a translucent
|
|
72
|
+
* ancestor fades its background along with the text), then over the page
|
|
73
|
+
* canvas.
|
|
74
|
+
*
|
|
75
|
+
* @param text - Text color (undefined: the background alone)
|
|
76
|
+
* @param backgrounds - Backgrounds with their opacity, the element's own first
|
|
77
|
+
* @param canvasDark - The page canvas is dark
|
|
78
|
+
* @returns The text pixel, the background pixel and whether a background
|
|
79
|
+
* image or gradient was in the way
|
|
80
|
+
*/
|
|
81
|
+
function paintOver(text, backgrounds, canvasDark) {
|
|
82
|
+
let withText = text ?? CLEAR;
|
|
83
|
+
let without = CLEAR;
|
|
84
|
+
let overImage = false;
|
|
85
|
+
for (const layer of backgrounds) {
|
|
86
|
+
if (layer.image && without.a < 0.999)
|
|
87
|
+
overImage = true;
|
|
88
|
+
const color = parseColor(layer.color);
|
|
89
|
+
if (color && color.a > 0) {
|
|
90
|
+
withText = composite(withText, color);
|
|
91
|
+
without = composite(without, color);
|
|
92
|
+
}
|
|
93
|
+
const opacity = layer.opacity ?? 1;
|
|
94
|
+
withText = { ...withText, a: withText.a * opacity };
|
|
95
|
+
without = { ...without, a: without.a * opacity };
|
|
96
|
+
}
|
|
97
|
+
const canvas = CANVAS[canvasDark ? 'dark' : 'light'];
|
|
36
98
|
return {
|
|
37
|
-
|
|
38
|
-
|
|
99
|
+
text: composite(withText, canvas),
|
|
100
|
+
background: composite(without, canvas),
|
|
101
|
+
overImage,
|
|
39
102
|
};
|
|
40
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Whether the element's own background lets what is behind it through (the
|
|
106
|
+
* background behind its text comes from an ancestor or the canvas).
|
|
107
|
+
*
|
|
108
|
+
* @param backgrounds - Backgrounds, the element's own first
|
|
109
|
+
* @returns True when its own background is not opaque
|
|
110
|
+
*/
|
|
111
|
+
function ownBackgroundTranslucent(backgrounds) {
|
|
112
|
+
const own = parseColor(backgrounds[0]?.color ?? '');
|
|
113
|
+
return !own || own.a < 0.999;
|
|
114
|
+
}
|
|
41
115
|
/**
|
|
42
116
|
* The background behind the element's text: its own and its ancestors'
|
|
43
|
-
* backgrounds composited
|
|
117
|
+
* backgrounds composited with their opacity over the page canvas.
|
|
44
118
|
*
|
|
45
119
|
* @param backgrounds - Backgrounds, the element's own first
|
|
46
120
|
* @param canvasDark - The page canvas is dark
|
|
47
121
|
* @returns Opaque background, whether it came from an ancestor and whether an image was in the way
|
|
48
122
|
*/
|
|
49
123
|
export function effectiveBackground(backgrounds, canvasDark) {
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (!color || color.a === 0)
|
|
57
|
-
continue;
|
|
58
|
-
layers.push(color);
|
|
59
|
-
if (color.a >= 0.999)
|
|
60
|
-
break;
|
|
61
|
-
}
|
|
62
|
-
const base = layers[layers.length - 1];
|
|
63
|
-
let color = base && base.a >= 0.999 ? base : CANVAS[canvasDark ? 'dark' : 'light'];
|
|
64
|
-
const translucent = base && base.a >= 0.999 ? layers.slice(0, -1) : layers;
|
|
65
|
-
for (const layer of [...translucent].reverse())
|
|
66
|
-
color = composite(layer, color);
|
|
67
|
-
const own = parseColor(backgrounds[0]?.color ?? '');
|
|
68
|
-
return { color, inherited: !own || own.a < 0.999, overImage };
|
|
124
|
+
const painted = paintOver(undefined, backgrounds, canvasDark);
|
|
125
|
+
return {
|
|
126
|
+
color: painted.background,
|
|
127
|
+
inherited: ownBackgroundTranslucent(backgrounds),
|
|
128
|
+
overImage: painted.overImage,
|
|
129
|
+
};
|
|
69
130
|
}
|
|
70
131
|
/**
|
|
71
|
-
* Contrast of the text color with the background behind it
|
|
132
|
+
* Contrast of the text color with the background behind it, both painted
|
|
133
|
+
* as the browser composites them ({@link paintOver}), with what makes the
|
|
134
|
+
* number approximate (blend modes, filters, content behind or on top).
|
|
72
135
|
*
|
|
73
136
|
* @param style - Computed styles (color, font size and weight)
|
|
74
|
-
* @param raw - Backgrounds
|
|
137
|
+
* @param raw - Backgrounds, the page canvas, opacity and paint risks
|
|
75
138
|
* @returns Ratio (rounded down to 2 decimals), level and background
|
|
76
139
|
*/
|
|
77
140
|
export function textContrast(style, raw) {
|
|
@@ -79,18 +142,19 @@ export function textContrast(style, raw) {
|
|
|
79
142
|
if (!color)
|
|
80
143
|
return undefined;
|
|
81
144
|
const opacity = raw.opacity ?? 1;
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
const ratio = Math.floor(contrastRatio(text, background.color) * 100) / 100;
|
|
145
|
+
const painted = paintOver(color, raw.backgrounds, raw.canvasDark);
|
|
146
|
+
const ratio = Math.floor(contrastRatio(painted.text, painted.background) * 100) / 100;
|
|
85
147
|
const size = pxNumber(style['font-size']) ?? 16;
|
|
86
148
|
const weight = Number(style['font-weight'] ?? 400);
|
|
149
|
+
const approximate = raw.paintRisks ?? [];
|
|
87
150
|
return {
|
|
88
151
|
ratio,
|
|
89
152
|
level: contrastLevel(ratio, size, weight),
|
|
90
|
-
background: toHex(background
|
|
91
|
-
...(
|
|
92
|
-
...(
|
|
153
|
+
background: toHex(painted.background),
|
|
154
|
+
...(ownBackgroundTranslucent(raw.backgrounds) && { inherited: true }),
|
|
155
|
+
...(painted.overImage && { overImage: true }),
|
|
93
156
|
...(opacity < 1 && { opacity: Math.round(opacity * 100) / 100 }),
|
|
157
|
+
...(approximate.length > 0 && { approximate }),
|
|
94
158
|
};
|
|
95
159
|
}
|
|
96
160
|
/**
|
|
@@ -188,40 +252,56 @@ function fontFields(style) {
|
|
|
188
252
|
};
|
|
189
253
|
}
|
|
190
254
|
/**
|
|
191
|
-
* The text group. Elements with text (or
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
* differs
|
|
255
|
+
* The text group. Elements with text (or text fields) get the full group,
|
|
256
|
+
* read from whatever draws the text (the element, or the descendant with
|
|
257
|
+
* most of it, named in `holder`): font with the rendered font, size, color,
|
|
258
|
+
* alignment, contrast (not for text no one can see: not rendered,
|
|
259
|
+
* `opacity: 0` on it or an ancestor, `visibility: hidden`) and the
|
|
260
|
+
* non-default extras. Containers get only what differs from their parent,
|
|
261
|
+
* with the font their text was rendered in when that text has the
|
|
262
|
+
* container's family. Nothing for an element without text (an icon button,
|
|
263
|
+
* a checkbox).
|
|
197
264
|
*
|
|
198
|
-
* @param
|
|
199
|
-
* @param parentStyle - Computed styles of the layout parent
|
|
265
|
+
* @param styles - Computed styles of the element, its parent and its text holder
|
|
200
266
|
* @param raw - Page-side measurements
|
|
201
267
|
* @param fonts - Platform fonts of the text
|
|
202
268
|
* @returns Text group, or undefined when there is nothing to say
|
|
203
269
|
*/
|
|
204
|
-
export function buildText(
|
|
205
|
-
const
|
|
270
|
+
export function buildText(styles, raw, fonts) {
|
|
271
|
+
const { style, parentStyle, holderStyle } = styles;
|
|
206
272
|
if (raw.textual) {
|
|
207
|
-
const
|
|
208
|
-
const
|
|
273
|
+
const textStyle = raw.textHolder && holderStyle ? holderStyle : style;
|
|
274
|
+
const fields = fontFields(textStyle);
|
|
275
|
+
const gradientFill = (textStyle['background-clip'] ?? '').includes('text') &&
|
|
276
|
+
(parseColor(textStyle['-webkit-text-fill-color'] ?? '')?.a ?? 1) === 0;
|
|
277
|
+
const seen = raw.rendered !== false &&
|
|
278
|
+
(raw.opacity ?? 1) > 0 &&
|
|
279
|
+
textStyle['visibility'] !== 'hidden' &&
|
|
280
|
+
!gradientFill;
|
|
281
|
+
const contrast = seen ? textContrast(textStyle, raw) : undefined;
|
|
209
282
|
return {
|
|
283
|
+
...(textStyle !== style && raw.textHolder && { holder: raw.textHolder }),
|
|
210
284
|
...fields,
|
|
211
|
-
...renderedFont(fields.family ?? '', fonts),
|
|
285
|
+
...renderedFont(fields.family ?? '', fonts, raw.familyLoaded),
|
|
212
286
|
...(contrast && { contrast }),
|
|
213
|
-
...textExtras(
|
|
214
|
-
align: alignOf(
|
|
287
|
+
...textExtras(textStyle),
|
|
288
|
+
align: alignOf(textStyle),
|
|
289
|
+
...(raw.truncated && { truncated: true }),
|
|
290
|
+
...(gradientFill && { gradientFill: true }),
|
|
215
291
|
};
|
|
216
292
|
}
|
|
217
|
-
if (!parentStyle)
|
|
293
|
+
if (!parentStyle || raw.hasText === false)
|
|
218
294
|
return undefined;
|
|
295
|
+
const fields = fontFields(style);
|
|
219
296
|
const parentFields = { ...fontFields(parentStyle), ...textExtras(parentStyle) };
|
|
220
297
|
const own = { ...fields, ...textExtras(style) };
|
|
221
298
|
const differing = Object.fromEntries(Object.entries(own).filter(([key, value]) => parentFields[key] !== value));
|
|
222
299
|
if (Object.keys(differing).length === 0)
|
|
223
300
|
return undefined;
|
|
224
|
-
|
|
301
|
+
const sameFamily = !holderStyle || holderStyle['font-family'] === style['font-family'];
|
|
302
|
+
return differing.family && sameFamily
|
|
303
|
+
? { ...differing, ...renderedFont(differing.family, fonts, raw.familyLoaded) }
|
|
304
|
+
: differing;
|
|
225
305
|
}
|
|
226
306
|
/**
|
|
227
307
|
* Cut a long value.
|
|
@@ -233,7 +313,8 @@ function cut(text) {
|
|
|
233
313
|
return text.length > IMAGE_TEXT_LENGTH ? `${text.slice(0, IMAGE_TEXT_LENGTH)}…` : text;
|
|
234
314
|
}
|
|
235
315
|
/**
|
|
236
|
-
* Background layers: images and gradients (top first),
|
|
316
|
+
* Background layers: images and gradients (top first), each with its own
|
|
317
|
+
* size and position when they are not the defaults, then the color.
|
|
237
318
|
*
|
|
238
319
|
* @param style - Computed styles
|
|
239
320
|
* @returns Fills
|
|
@@ -241,25 +322,46 @@ function cut(text) {
|
|
|
241
322
|
export function buildFills(style) {
|
|
242
323
|
const fills = [];
|
|
243
324
|
const image = style['background-image'];
|
|
244
|
-
const size = style['background-size'];
|
|
245
325
|
if (image && image !== 'none') {
|
|
246
|
-
|
|
326
|
+
const sizes = splitTopLevel(style['background-size'] ?? 'auto');
|
|
327
|
+
const xs = splitTopLevel(style['background-position-x'] ?? '0%');
|
|
328
|
+
const ys = splitTopLevel(style['background-position-y'] ?? '0%');
|
|
329
|
+
const positions = xs.map((x, i) => `${x} ${ys[i % ys.length] ?? '0%'}`);
|
|
330
|
+
splitTopLevel(image).forEach((layer, i) => {
|
|
331
|
+
const size = sizes[i % sizes.length] ?? 'auto';
|
|
332
|
+
const position = positions[i % positions.length] ?? '0% 0%';
|
|
247
333
|
const value = cut(normalizeCssValue(shortUrls(layer)));
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
});
|
|
256
|
-
}
|
|
334
|
+
fills.push({
|
|
335
|
+
type: layer.includes('gradient(') ? 'gradient' : 'image',
|
|
336
|
+
value,
|
|
337
|
+
...(size !== 'auto' && size !== 'auto auto' && { size: normalizeCssValue(size) }),
|
|
338
|
+
...(position !== '0% 0%' && { position: normalizeCssValue(position) }),
|
|
339
|
+
});
|
|
340
|
+
});
|
|
257
341
|
}
|
|
258
342
|
const color = hexColor(style['background-color'] ?? 'transparent');
|
|
259
343
|
if (color !== 'transparent')
|
|
260
344
|
fills.push({ type: 'solid', color });
|
|
261
345
|
return fills;
|
|
262
346
|
}
|
|
347
|
+
/**
|
|
348
|
+
* How an SVG element is painted: its `fill` and `stroke` (with the width).
|
|
349
|
+
*
|
|
350
|
+
* @param style - Computed styles
|
|
351
|
+
* @param raw - Whether it is an SVG element
|
|
352
|
+
* @returns Paint, or undefined for an HTML element
|
|
353
|
+
*/
|
|
354
|
+
export function buildSvgPaint(style, raw) {
|
|
355
|
+
if (!raw.svg)
|
|
356
|
+
return undefined;
|
|
357
|
+
const paint = (value) => normalizeCssValue(shortUrls(hexColor(value ?? 'none')));
|
|
358
|
+
const stroke = paint(style['stroke']);
|
|
359
|
+
return {
|
|
360
|
+
fill: paint(style['fill']),
|
|
361
|
+
stroke,
|
|
362
|
+
...(stroke !== 'none' && { strokeWidth: cssLength(style['stroke-width'] ?? '1px') }),
|
|
363
|
+
};
|
|
364
|
+
}
|
|
263
365
|
/**
|
|
264
366
|
* Border sides that show (a style other than none/hidden and a width): one
|
|
265
367
|
* `all` stroke when the four are equal.
|
|
@@ -421,6 +523,7 @@ export function buildGeneratedPseudo(pseudo, hostColor) {
|
|
|
421
523
|
content: shortUrls(content),
|
|
422
524
|
...(display && display !== 'inline' && { display }),
|
|
423
525
|
...(position && position !== 'static' && { position }),
|
|
526
|
+
...(position && position !== 'static' && { inset: insetOf(style) }),
|
|
424
527
|
...(pseudo.size && { size: pseudo.size }),
|
|
425
528
|
...(style['color'] && style['color'] !== hostColor && { color: hexColor(style['color']) }),
|
|
426
529
|
...(fills.length > 0 && { fills }),
|
|
@@ -430,6 +533,15 @@ export function buildGeneratedPseudo(pseudo, hostColor) {
|
|
|
430
533
|
...(opacity !== 1 && { opacity }),
|
|
431
534
|
};
|
|
432
535
|
}
|
|
536
|
+
/**
|
|
537
|
+
* Offsets of a positioned box, as one 1-4 value shorthand.
|
|
538
|
+
*
|
|
539
|
+
* @param style - Computed styles
|
|
540
|
+
* @returns e.g. `auto 50% -9 0`
|
|
541
|
+
*/
|
|
542
|
+
function insetOf(style) {
|
|
543
|
+
return sidesShorthand(['top', 'right', 'bottom', 'left'].map((side) => normalizeCssValue(style[side] ?? 'auto')));
|
|
544
|
+
}
|
|
433
545
|
/**
|
|
434
546
|
* The pseudo group: generated `::before`/`::after` and the placeholder color.
|
|
435
547
|
*
|
|
@@ -14,6 +14,14 @@ import type { Declaration } from './inspectCascade.js';
|
|
|
14
14
|
* @param cdp - CDP connection
|
|
15
15
|
*/
|
|
16
16
|
export declare function trackStyleSheets(cdp: CDPConnection): void;
|
|
17
|
+
/**
|
|
18
|
+
* The stylesheet headers seen on a connection (after {@link trackStyleSheets}
|
|
19
|
+
* and `CSS.enable`).
|
|
20
|
+
*
|
|
21
|
+
* @param cdp - CDP connection
|
|
22
|
+
* @returns Headers
|
|
23
|
+
*/
|
|
24
|
+
export declare function styleSheetHeaders(cdp: CDPConnection): Iterable<Protocol.CSS.CSSStyleSheetHeader>;
|
|
17
25
|
/**
|
|
18
26
|
* The rules that match an element, with its inline style and what its
|
|
19
27
|
* ancestors pass down, or why they are missing.
|
|
@@ -34,4 +42,15 @@ export declare function matchedStyles(cdp: CDPConnection, nodeId: number, budget
|
|
|
34
42
|
* @returns e.g. `.btn-primary (bootstrap.min.css:5:52628)`, `style attribute`, `browser default`
|
|
35
43
|
*/
|
|
36
44
|
export declare function sourceLabel(declaration: Declaration, cdp: CDPConnection): string;
|
|
45
|
+
/**
|
|
46
|
+
* A stylesheet position as `file:line[:column]`.
|
|
47
|
+
*
|
|
48
|
+
* @param header - Stylesheet header (unknown: just the line)
|
|
49
|
+
* @param line - 0-based line within the stylesheet
|
|
50
|
+
* @param column - 0-based column
|
|
51
|
+
* @returns e.g. `app.css:12`, `bootstrap.min.css:5:52628`, `<style> in index.html:40`,
|
|
52
|
+
* `constructed stylesheet`, `<style> added by a script` (a sheet a script created and
|
|
53
|
+
* filled with `insertRule`: its lines are not in any file)
|
|
54
|
+
*/
|
|
55
|
+
export declare function stylesheetPositionLabel(header: Protocol.CSS.CSSStyleSheetHeader | undefined, line: number | undefined, column: number | undefined): string;
|
|
37
56
|
//# sourceMappingURL=inspectRules.d.ts.map
|
|
@@ -27,6 +27,16 @@ export function trackStyleSheets(cdp) {
|
|
|
27
27
|
headers.delete(styleSheetId);
|
|
28
28
|
});
|
|
29
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* The stylesheet headers seen on a connection (after {@link trackStyleSheets}
|
|
32
|
+
* and `CSS.enable`).
|
|
33
|
+
*
|
|
34
|
+
* @param cdp - CDP connection
|
|
35
|
+
* @returns Headers
|
|
36
|
+
*/
|
|
37
|
+
export function styleSheetHeaders(cdp) {
|
|
38
|
+
return headersByConnection.get(cdp)?.values() ?? [];
|
|
39
|
+
}
|
|
30
40
|
/**
|
|
31
41
|
* The rules that match an element, with its inline style and what its
|
|
32
42
|
* ancestors pass down, or why they are missing.
|
|
@@ -77,7 +87,7 @@ export function sourceLabel(declaration, cdp) {
|
|
|
77
87
|
const header = source.styleSheetId
|
|
78
88
|
? headersByConnection.get(cdp)?.get(source.styleSheetId)
|
|
79
89
|
: undefined;
|
|
80
|
-
return `${source.selector ?? ''} (${
|
|
90
|
+
return `${source.selector ?? ''} (${stylesheetPositionLabel(header, source.line, source.column)})`;
|
|
81
91
|
}
|
|
82
92
|
/**
|
|
83
93
|
* A stylesheet position as `file:line[:column]`.
|
|
@@ -85,17 +95,23 @@ export function sourceLabel(declaration, cdp) {
|
|
|
85
95
|
* @param header - Stylesheet header (unknown: just the line)
|
|
86
96
|
* @param line - 0-based line within the stylesheet
|
|
87
97
|
* @param column - 0-based column
|
|
88
|
-
* @returns e.g. `app.css:12`, `bootstrap.min.css:5:52628`, `<style> in index.html:40`,
|
|
98
|
+
* @returns e.g. `app.css:12`, `bootstrap.min.css:5:52628`, `<style> in index.html:40`,
|
|
99
|
+
* `constructed stylesheet`, `<style> added by a script` (a sheet a script created and
|
|
100
|
+
* filled with `insertRule`: its lines are not in any file)
|
|
89
101
|
*/
|
|
90
|
-
function
|
|
102
|
+
export function stylesheetPositionLabel(header, line, column) {
|
|
91
103
|
if (!header)
|
|
92
104
|
return line === undefined ? 'stylesheet' : `stylesheet:${line + 1}`;
|
|
93
105
|
if (header.isConstructed)
|
|
94
106
|
return 'constructed stylesheet';
|
|
95
107
|
const file = fileName(header.sourceURL) || 'page';
|
|
96
|
-
const absoluteLine = (line ?? 0) + (header.isInline ? header.startLine : 0) + 1;
|
|
97
108
|
const where = header.isInline ? `<style> in ${file}` : file;
|
|
109
|
+
if (header.isMutable && !header.sourceURL)
|
|
110
|
+
return `<style> added by a script`;
|
|
111
|
+
const absoluteLine = (line ?? 0) + (header.isInline ? header.startLine : 0) + 1;
|
|
112
|
+
const firstLine = header.isInline && (line ?? 0) === 0;
|
|
113
|
+
const absoluteColumn = (column ?? 0) + (firstLine ? header.startColumn : 0) + 1;
|
|
98
114
|
const minified = header.endLine - header.startLine < 10 && (column ?? 0) > 200;
|
|
99
|
-
return minified ? `${where}:${absoluteLine}:${
|
|
115
|
+
return minified ? `${where}:${absoluteLine}:${absoluteColumn}` : `${where}:${absoluteLine}`;
|
|
100
116
|
}
|
|
101
117
|
//# sourceMappingURL=inspectRules.js.map
|