styleproof 2.3.0 → 2.3.1

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/CHANGELOG.md CHANGED
@@ -7,6 +7,20 @@ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.3.1] - 2026-06-23
11
+
12
+ ### Fixed
13
+
14
+ - **Animation freeze is now deterministic for content that mounts during the
15
+ settle.** Motion longhands (declared `animation`/`transition`) were read _before_
16
+ the settle, so an element that mounts while the page settles — a status glyph
17
+ gated on a snapshot fetch — missed that read: its declared `animation-duration`
18
+ was folded back on a run where it mounted early but left frozen to `0s` on a run
19
+ where it mounted late, surfacing as a self-check `animation-duration: 0s ↔ 1.6s`
20
+ non-deterministic failure. Motion is now read on the settled DOM (the freeze is
21
+ lifted only for that read), so a late-mounted animated element is captured
22
+ identically every run.
23
+
10
24
  ## [2.3.0] - 2026-06-23
11
25
 
12
26
  ### Added
package/dist/capture.js CHANGED
@@ -562,15 +562,26 @@ export async function captureStyleMap(page, options = {}) {
562
562
  // can't share a module-scope function) call ONE definition — no duplicated source.
563
563
  // It persists on `window` for every evaluate below (no navigation between them).
564
564
  await page.evaluate(injectPathOf);
565
- // Motion longhands first (FREEZE_CSS would null them), then everything else.
566
- // Motion never carries text it's a settled end state of declared motion.
567
- const motion = await page.evaluate(capturePage, { ignore, motionOnly: true, captureText: false });
568
- await page.addStyleTag({ content: FREEZE_CSS });
565
+ // Freeze motion BEFORE settling: animating elements would otherwise read as
566
+ // perpetual churn during the settle, and any content that mounts during the
567
+ // settle must be frozen by the time we read it below.
568
+ const freezeTag = await page.addStyleTag({ content: FREEZE_CSS });
569
569
  // Settle: wait for async content to finish painting so base and head capture
570
570
  // the same loaded state, and collect any region still changing on its own
571
571
  // (a live stream/ticker) to exclude — animations are frozen above, so only
572
572
  // real content/layout churn lands here.
573
573
  const volatile = await detectVolatile(page, ignore, stabilize, captureText, options.pendingRequests);
574
+ // Motion longhands (transition/animation) are read separately so declared
575
+ // motion is verified even though every other value is a frozen end state.
576
+ // Read them on the SETTLED DOM, not before it: capturing pre-settle missed any
577
+ // element that mounts DURING the settle (e.g. a late status glyph), so its
578
+ // declared `animation-duration` was folded back on the run where it happened to
579
+ // mount early but left frozen (0s) on the run where it mounted late — a
580
+ // self-check "non-deterministic" flip. Lift the freeze just for this read (it
581
+ // nulls motion to 0s), then re-apply it before reading everything else.
582
+ await freezeTag.evaluate((el) => el.remove());
583
+ const motion = await page.evaluate(capturePage, { ignore, motionOnly: true, captureText: false });
584
+ await page.addStyleTag({ content: FREEZE_CSS });
574
585
  const base = await page.evaluate(capturePage, { ignore, motionOnly: false, captureText, captureComponent });
575
586
  dropVolatile(base.elements, volatile);
576
587
  warnUntraversed(base.shadowHosts, base.sameOriginFrames);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "styleproof",
3
- "version": "2.3.0",
3
+ "version": "2.3.1",
4
4
  "description": "Catch every CSS change before it ships — review PRs and certify refactors by the browser's computed styles, not pixels. Works with any styling system.",
5
5
  "keywords": [
6
6
  "playwright",