@hueest/xray 0.6.0 → 0.7.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/LICENSE +21 -0
- package/README.md +14 -12
- package/dist/client.d.ts +42 -51
- package/dist/client.js +134 -141
- package/dist/core.d.ts +34 -44
- package/dist/core.js +27 -33
- package/dist/css-escape-DJ-BsrNm.js +47 -0
- package/dist/hud.d.ts +7 -8
- package/dist/hud.js +5 -5
- package/dist/index.d.ts +251 -284
- package/dist/index.js +292 -338
- package/dist/measure-CUQxB-Ic.d.ts +524 -0
- package/dist/{plate-BwJUgHDc.js → plate-CXIh5_OB.js} +52 -59
- package/dist/react.core-BS2yvqeh.js +301 -0
- package/dist/react.core-BkJoCgWJ.d.ts +115 -0
- package/dist/react.d.ts +11 -13
- package/dist/react.dev.d.ts +4 -6
- package/dist/react.dev.js +54 -61
- package/dist/react.js +21 -21
- package/dist/{project-BAXKpnfF.js → serialize-Cj-EHvMv.js} +872 -1026
- package/package.json +8 -6
- package/virtual.d.ts +25 -32
- package/dist/css-escape-N7bOusGW.js +0 -52
- package/dist/react.core-DeEli0Lp.js +0 -307
- package/dist/react.core-sJfIcaXX.d.ts +0 -102
- package/dist/serialize-BqbQVxYl.d.ts +0 -564
package/dist/core.js
CHANGED
|
@@ -1,22 +1,20 @@
|
|
|
1
|
-
import { a as ROOT_ATTR, d as composeCss, f as emptyPlate, o as ROOT_CLASS, t as BASE_CSS } from "./plate-
|
|
2
|
-
import { a as serializePlate, c as defineXrayCaptureWalker, i as collectRefs, l as
|
|
3
|
-
import { t as escapeStyleText } from "./css-escape-
|
|
1
|
+
import { a as ROOT_ATTR, d as composeCss, f as emptyPlate, o as ROOT_CLASS, t as BASE_CSS } from "./plate-CXIh5_OB.js";
|
|
2
|
+
import { a as serializePlate, c as defineXrayCaptureWalker, i as collectRefs, l as distilPlate, o as CaptureTooLargeError, s as captureView, t as serializePlateIR } from "./serialize-Cj-EHvMv.js";
|
|
3
|
+
import { t as escapeStyleText } from "./css-escape-DJ-BsrNm.js";
|
|
4
4
|
//#region src/core.ts
|
|
5
5
|
/**
|
|
6
|
-
* Capture a live DOM subtree straight to the two renderable artifacts: the
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* roots). Render however suits: `renderPlateHtml(plate, composeCss(css))`,
|
|
14
|
-
* or `<Skeleton plate={plate} css={composeCss(css)}>` with the React adapter.
|
|
6
|
+
* Capture a live DOM subtree straight to the two renderable artifacts: the structural `plate`
|
|
7
|
+
* (tree, lowered to chunks) and its scoped `css` string — independent parts, per the two-artifact
|
|
8
|
+
* contract. Runs the same uniform pipeline the dev client does for a single View — measure
|
|
9
|
+
* (`captureView`), distil (`distilPlate`), project (`serializePlateIR` → the structured
|
|
10
|
+
* `StoredPlate`), then lower to chunks (`serializePlate`) — in one call. `roots` are the top-level
|
|
11
|
+
* elements to capture (a component's rendered roots). Render however suits: `renderPlateHtml(plate,
|
|
12
|
+
* composeCss(css))`, or `<Skeleton plate={plate} css={composeCss(css)}>` with the React adapter.
|
|
15
13
|
*
|
|
16
|
-
* `options.walker` is the public programmable capture walker (ADR 0018
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
14
|
+
* `options.walker` is the public programmable capture walker (ADR 0018): the same
|
|
15
|
+
* `XrayCaptureWalker` the `<Skeleton captureWalker>` prop threads through in dev, available here
|
|
16
|
+
* for driving capture directly. It is capture-only and never persisted into the returned
|
|
17
|
+
* artifacts.
|
|
20
18
|
*/
|
|
21
19
|
function captureElement(roots, options) {
|
|
22
20
|
const plateIR = captureView(roots, {
|
|
@@ -25,7 +23,7 @@ function captureElement(roots, options) {
|
|
|
25
23
|
captureRootIsBoundary: options.captureRootIsBoundary
|
|
26
24
|
});
|
|
27
25
|
plateIR.name = options.name;
|
|
28
|
-
|
|
26
|
+
distilPlate(plateIR);
|
|
29
27
|
const stored = serializePlateIR(plateIR);
|
|
30
28
|
return {
|
|
31
29
|
plate: serializePlate(stored),
|
|
@@ -33,18 +31,15 @@ function captureElement(roots, options) {
|
|
|
33
31
|
};
|
|
34
32
|
}
|
|
35
33
|
/**
|
|
36
|
-
* Render a stitch-free Plate to an HTML string — the framework-neutral
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* `el.innerHTML = renderPlateHtml(plate, composeCss(css))` or React's
|
|
34
|
+
* Render a stitch-free Plate to an HTML string — the framework-neutral equivalent of `<Skeleton
|
|
35
|
+
* plate loading />`, for when you don't want to pull a framework adapter (demos, plain DOM, server
|
|
36
|
+
* strings). Drop it in with `el.innerHTML = renderPlateHtml(plate, composeCss(css))` or React's
|
|
40
37
|
* `dangerouslySetInnerHTML`.
|
|
41
38
|
*
|
|
42
|
-
* `css` is the caller's explicit input (two-artifact contract): pass
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* plates (a nested `<Skeleton>`) need an adapter to mount their child plates,
|
|
47
|
-
* so they throw here.
|
|
39
|
+
* `css` is the caller's explicit input (two-artifact contract): pass `composeCss(css)` for the
|
|
40
|
+
* standard BASE_CSS + plate-rules composition (BASE_CSS is what makes bones paint and pulse), the
|
|
41
|
+
* raw capture css if the base rules are already on the page, or your own composition. Stitched
|
|
42
|
+
* plates (a nested `<Skeleton>`) need an adapter to mount their child plates, so they throw here.
|
|
48
43
|
*/
|
|
49
44
|
function renderPlateHtml(plate, css) {
|
|
50
45
|
const chunks = plate.chunks;
|
|
@@ -53,12 +48,11 @@ function renderPlateHtml(plate, css) {
|
|
|
53
48
|
return `<div ${ROOT_ATTR}="${plate.name}" class="${className}" aria-hidden="true" aria-busy="true"><style>${escapeStyleText(css)}</style>${chunksToHtml(chunks)}</div>`;
|
|
54
49
|
}
|
|
55
50
|
/**
|
|
56
|
-
* Flatten chunks to one HTML string. A `string` concatenates; a template chunk
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* and interpolated raw, exactly as the single-string path was before.
|
|
51
|
+
* Flatten chunks to one HTML string. A `string` concatenates; a template chunk (`{ t, n }`) expands
|
|
52
|
+
* to its cell repeated `n` times (the cell is stitch-free by construction); a stitch-free wrapper
|
|
53
|
+
* (`{ c, k }`) recurses inside a real `<div>`. A stitch (`{ r }`) resolves to a child plate at
|
|
54
|
+
* render and needs a framework adapter to mount, so a stitched plate throws here. Chunk HTML is
|
|
55
|
+
* xray-generated and safe to interpolate raw.
|
|
62
56
|
*/
|
|
63
57
|
function chunksToHtml(chunks) {
|
|
64
58
|
let html = "";
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
//#region src/css-escape.ts
|
|
2
|
+
/**
|
|
3
|
+
* Dependency-free raw-text safety for the one place a Plate's CSS string is interpolated into
|
|
4
|
+
* `<style>…</style>` markup.
|
|
5
|
+
*
|
|
6
|
+
* A plate's `css` is normally produced by the capture path (`filterLayoutDecls` + `classify`),
|
|
7
|
+
* which only ever emits well-formed `selector { prop: value }` rules — never a raw-text terminator.
|
|
8
|
+
* But a committed `plates/<name>.json` is UNTRUSTED at render time (it can be hand-edited or arrive
|
|
9
|
+
* over git, ADR 0023), and a corrupt/malicious `css` could carry a `</style>` or an HTML comment
|
|
10
|
+
* delimiter. `<style>` is a raw-text element: the parser ends the element at the first `</style` it
|
|
11
|
+
* sees and resumes parsing the rest as ordinary HTML, so an unescaped terminator in the CSS body
|
|
12
|
+
* turns the tail of the plate into live markup.
|
|
13
|
+
*
|
|
14
|
+
* The React text-child path (`<style>{css}</style>`) is already safe — React escapes the child —
|
|
15
|
+
* but the two STRING paths interpolate `css` directly into a markup string (`renderPlateHtml`
|
|
16
|
+
* builds an HTML string; `react.core.tsx` feeds one to `dangerouslySetInnerHTML`). Those must run
|
|
17
|
+
* the body through this helper first.
|
|
18
|
+
*
|
|
19
|
+
* This lives in its own dependency-free module ON PURPOSE: it is imported by render/browser paths,
|
|
20
|
+
* so it must NOT pull in the Node-only validation code (valibot). It neutralizes only the sequences
|
|
21
|
+
* that can escape a raw-text `<style>` context — a `<` that begins `</style`, and the HTML comment
|
|
22
|
+
* / CDATA delimiters the tokenizer treats specially inside raw text — by inserting a CSS-comment
|
|
23
|
+
* break (`/**/`) that the CSS parser ignores. It does not, and is not meant to, sanitize CSS
|
|
24
|
+
* semantically; POST-time validation (`validate.ts`) is what rejects junk declarations.
|
|
25
|
+
*
|
|
26
|
+
* @module
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Make a CSS body safe to interpolate into a `<style>…</style>` STRING. Breaks up the only
|
|
30
|
+
* sequences the HTML tokenizer acts on inside a raw-text `<style>` element, so none can terminate
|
|
31
|
+
* the element early or open a comment/CDATA run:
|
|
32
|
+
*
|
|
33
|
+
* - `</style` (the end-tag open, case-insensitive) — inserts the break between `<` and `/style` so
|
|
34
|
+
* the parser never matches the end tag.
|
|
35
|
+
* - `<!--`, `-->`, `<![CDATA[` — the comment/CDATA delimiters; split so neither a comment nor a CDATA
|
|
36
|
+
* section can open.
|
|
37
|
+
*
|
|
38
|
+
* The inserted `/**/` is an empty CSS comment: inert to the CSS parser (it cannot appear
|
|
39
|
+
* mid-token in a value the capture emits, and a stray one only ends a token early), so a
|
|
40
|
+
* well-formed plate is rendered byte-for-byte equivalently while a corrupt one can no longer break
|
|
41
|
+
* out of the style element.
|
|
42
|
+
*/
|
|
43
|
+
function escapeStyleText(css) {
|
|
44
|
+
return css.replace(/<(\/style)/gi, "</**/$1").replace(/<!--/g, "<!/**/--").replace(/-->/g, "--/**/>").replace(/<!\[CDATA\[/g, "<![/**/CDATA[");
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
47
|
+
export { escapeStyleText as t };
|
package/dist/hud.d.ts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
//#region src/hud.d.ts
|
|
2
2
|
/**
|
|
3
|
-
* The opt-in dev HUD (Astro-dev-toolbar-style): a small fixed badge. For each
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* session, so it reflects what's actually on disk.
|
|
3
|
+
* The opt-in dev HUD (Astro-dev-toolbar-style): a small fixed badge. For each plate it shows every
|
|
4
|
+
* detected width band — captured ones lit, the rest dim — sourced from the committed plate files
|
|
5
|
+
* (via `__XRAY__.coverage`), not the session, so it reflects what's actually on disk.
|
|
7
6
|
*
|
|
8
|
-
* It is also the controller for capture-all-views (ADR 0010): it probes for the
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
7
|
+
* It is also the controller for capture-all-views (ADR 0010): it probes for the companion extension
|
|
8
|
+
* (which announces itself via its content script) and shows a "Capture all views" button when
|
|
9
|
+
* present, or a one-line promotion when not. The sweep itself lives in the dev client
|
|
10
|
+
* (`__XRAY__.captureAllViews`).
|
|
12
11
|
*/
|
|
13
12
|
interface HudHandle {
|
|
14
13
|
dispose: () => void;
|
package/dist/hud.js
CHANGED
|
@@ -3,8 +3,8 @@ function isExtensionHello(value) {
|
|
|
3
3
|
return typeof value === "object" && value !== null && "source" in value && value.source === "xray-ext" && "kind" in value && value.kind === "hello";
|
|
4
4
|
}
|
|
5
5
|
/**
|
|
6
|
-
* A labelled checkbox bound to a sticky toggle store; reads the store on build
|
|
7
|
-
*
|
|
6
|
+
* A labelled checkbox bound to a sticky toggle store; reads the store on build so a console/URL
|
|
7
|
+
* flip stays in sync with the box at the next render.
|
|
8
8
|
*/
|
|
9
9
|
function toggleRow(store, text) {
|
|
10
10
|
const label = document.createElement("label");
|
|
@@ -19,9 +19,9 @@ function toggleRow(store, text) {
|
|
|
19
19
|
return label;
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
|
-
* Expand a plate's coverage into the full set of width bands, flagging which are
|
|
23
|
-
*
|
|
24
|
-
*
|
|
22
|
+
* Expand a plate's coverage into the full set of width bands, flagging which are captured. The
|
|
23
|
+
* breakpoints partition the width axis; a band is covered when a captured span matches it (spans
|
|
24
|
+
* align to band boundaries, ADR 0004).
|
|
25
25
|
*/
|
|
26
26
|
function bandsOf({ breakpoints, spans }) {
|
|
27
27
|
const sorted = [...breakpoints].toSorted((a, b) => a - b);
|