Skip to content

Implement plain direction fade API - #4

Merged
petekp merged 18 commits into
mainfrom
pkp/plain-direction-v1-fade
Jun 29, 2026
Merged

Implement plain direction fade API#4
petekp merged 18 commits into
mainfrom
pkp/plain-direction-v1-fade

Conversation

@petekp

@petekp petekp commented Jun 26, 2026

Copy link
Copy Markdown
Owner
  • Replaces the old public API with RTL/LTR-friendly directional utilities: fade, fade-y, fade-top, fade-bottom, fade-x, fade-start, and fade-end
  • Adds direction-aware horizontal routing, renamed reveal controls, clear/size updates, and fade-none/fade-always utilities

Reconciled with the deployed demo (rebased onto pkp/tw-shimmer-credit)

This branch was rebased from main onto pkp/tw-shimmer-credit, so the new API now sits on top of the latest demo/site work that's already deployed to pete.design. Because tw-shimmer-credit has no PR of its own, this PR now also carries its 7 demo commits (tw-shimmer credit, smoothed wave background, container depth/motion refinements, rewritten chat copy, regenerated demo CSS). Merging therefore brings main current with the deployed site and applies the plain-direction API in one shot. The API change itself is the two commits at the tip (Implement plain direction fade API, Address PR #4 review findings).

During the rebase, demo conflicts were resolved by taking the upstream design and re-applying the new API names (e.g. fade-size-2xl + fade/fade-always/fade-x/fade-reveal-sm), and the demo chat copy was updated from old vocabulary (fade-t, "range") to the new names (fade-top, "reveal").

Post-rebase validation

  • npm test — 16/16 (incl. the dist === fresh compile freshness gate and the plain-API inventory check that enforces REJECTED_CLASSES)
  • npm run verify — 9/9 verifiers green in real Chromium + WebKit, including RTL horizontal routing (15/15: fade-start→physical-right / fade-end→physical-left under dir=rtl, nested dir overrides, scroll(self inline)) and fade pixel masking (17/17)
  • Demo CSS regenerated from the new-API source; dist/tw-fade.css is fresh at 30,077 bytes (under the 55 KB cap)
  • MIGRATING.md is the agent-oriented 0.7.0 upgrade guide

https://claude.ai/code/session_01B1Gn7DoGHbzGCLMbA72Stj

petekp added a commit that referenced this pull request Jun 27, 2026
Engine fix:
- src/tw-fade.css: add neutral block-axis defaults to the shared base
  block so a nested vertical fade no longer inherits a parent's t/b
  animation/timeline/range hook and run a spurious (inert) second
  scroll animation. Mirrors the existing l/r indirection pattern.
  Rebuilt dist/tw-fade.css (30,079 B, well under the 55,000 cap).

Tests:
- Document REJECTED_CLASSES intent: both the old physical names and the
  fully-logical inline/block aliases are deliberately excluded, so
  re-adding either is a conscious choice, not a silent regression.

Docs:
- MIGRATING.md: rewrite as a concise guide for humans and coding agents
  alike — inclusive lead + explicit agent callout, ordered
  judgment -> mechanical -> verify steps, full rename tables, the
  physical->logical RTL caveat, and a token-boundary verification grep.
  Drop the maintainer-only demo resync note.
- README.md: qualify the RTL guarantees with the :dir() floor, rewrite
  Browser Support as a per-feature table, and point the migration
  section at the agent-executable guide.

Packaging / release:
- package.json: add rtl/direction-aware/logical-properties/bidi
  keywords; ship CHANGELOG.md.
- CHANGELOG.md: new Keep a Changelog 0.7.0 breaking-rename entry.
- .github/workflows/ci.yml: run npm test + the Chromium/WebKit verify
  chain on PRs and pushes to main, closing the PR-time enforcement gap.

Claude-Session: https://claude.ai/code/session_01B1Gn7DoGHbzGCLMbA72Stj
petekp added 2 commits June 26, 2026 20:03
Engine fix:
- src/tw-fade.css: add neutral block-axis defaults to the shared base
  block so a nested vertical fade no longer inherits a parent's t/b
  animation/timeline/range hook and run a spurious (inert) second
  scroll animation. Mirrors the existing l/r indirection pattern.
  Rebuilt dist/tw-fade.css (30,079 B, well under the 55,000 cap).

Tests:
- Document REJECTED_CLASSES intent: both the old physical names and the
  fully-logical inline/block aliases are deliberately excluded, so
  re-adding either is a conscious choice, not a silent regression.

Docs:
- MIGRATING.md: rewrite as a concise guide for humans and coding agents
  alike — inclusive lead + explicit agent callout, ordered
  judgment -> mechanical -> verify steps, full rename tables, the
  physical->logical RTL caveat, and a token-boundary verification grep.
  Drop the maintainer-only demo resync note.
- README.md: qualify the RTL guarantees with the :dir() floor, rewrite
  Browser Support as a per-feature table, and point the migration
  section at the agent-executable guide.

Packaging / release:
- package.json: add rtl/direction-aware/logical-properties/bidi
  keywords; ship CHANGELOG.md.
- CHANGELOG.md: new Keep a Changelog 0.7.0 breaking-rename entry.
- .github/workflows/ci.yml: run npm test + the Chromium/WebKit verify
  chain on PRs and pushes to main, closing the PR-time enforcement gap.

Claude-Session: https://claude.ai/code/session_01B1Gn7DoGHbzGCLMbA72Stj
@petekp
petekp force-pushed the pkp/plain-direction-v1-fade branch from ac31867 to e64b5e9 Compare June 27, 2026 03:07
petekp added 9 commits June 26, 2026 22:34
Demo: new "Direction" segmented control (LTR/RTL) on the advanced type-specimen, ordered Edges → Direction → Fade size → Ramp. Flipping direction swaps fade-start/fade-end to the opposite physical edge via :dir(rtl); a safeguard auto-enables a horizontal edge when none is set. Includes the a11y Label-in-Name fix and RTL padding-inline-end symmetry fix.

API rename: fade-reveal-* → fade-ramp-* (theme scale --fade-ramp-*, internal --tw-fade-ramp / --tw-fade-ramp-active, keyframes tw-fade-ramp-*, data-fade-ramp-*). "ramp" describes the scroll-travel distance over which a fade eases in/out, rather than implying nearness to the edge. The English verb "reveal" is deliberately preserved in prose/comments. Docs (README/MIGRATING/CHANGELOG), tests, verifiers, and generated dist/demo CSS updated accordingly.

npm test 16/16; npm run verify exit 0 (all 9 verifiers green).

Claude-Session: https://claude.ai/code/session_01B1Gn7DoGHbzGCLMbA72Stj
The demo runtime smoke drove the scroll-linked wave field with
`body.scrollTo({behavior:'instant'})` + a fixed 240ms wait, then asserted
the SVG wave morphed. This passed on macOS WebKit but failed only in CI's
headless Linux WebKit: that engine doesn't reliably emit a native `scroll`
event for a *programmatic* position change on the overflow body, so the
field's scroll listener never fired and the wave stayed frozen at its top
geometry (1629 -> 1629).

Set scrollTop directly, dispatch the `scroll` event the field listens for,
and poll (rAF-driven) for the morph instead of betting on a single fixed
delay. rAF itself works in CI WebKit (the mouse-spring check relies on it),
so the poll converges; the manual dispatch covers the missing native event.
This is a CI-environment artifact, not a real-user bug — genuine touch
scrolls do fire the event.

Claude-Session: https://claude.ai/code/session_01B1Gn7DoGHbzGCLMbA72Stj
Drop the .dir-toggle-group background fill from 62% to 35% of
--demo-page-bg so the dark tint behind the Direction toggle reads softer.

Claude-Session: https://claude.ai/code/session_01B1Gn7DoGHbzGCLMbA72Stj
The beveled inner-border highlight on the demo containers (install-snippet,
tuning-card, feature-column, support-tooltip, etc.) drew a circular arc while
the hosts use corner-shape: superellipse(1.35). corner-shape is not inherited
and border-radius: inherit copies only the radius, so the highlight diverged
from the host edge at every corner regardless of whether it was drawn with a
mask, box-shadow, or border.

- Add corner-shape: inherit to the highlight pseudo-elements so the hairline
  follows the host squircle exactly. Unsupported browsers drop it and both host
  and highlight stay round.
- Rework the single per-side border (which met its top/side/bottom colors at a
  hard miter seam at each corner) into two uniform-color borders: ::before is a
  light top layer, ::after a dark bottom layer, each faded with a linear-gradient
  mask so the catch and shadow taper off smoothly as they wrap the corner.
- Add --demo-inner-border-taper to control the falloff distance.

Claude-Session: https://claude.ai/code/session_01B1Gn7DoGHbzGCLMbA72Stj
- CHANGELOG.md: fix the Changed-section wording and note that fade-x is now
  direction-aware.
- test/plugin.test.mjs: add a test asserting the shipped CSS carries none of the
  retired reveal/range token names.
- demo/index.html: update the tw-shimmer credit from 475k+ to 500k+ weekly npm
  downloads.

Claude-Session: https://claude.ai/code/session_01B1Gn7DoGHbzGCLMbA72Stj
- Edge transparency now rides --tw-fade-alpha-* (= min(1, t * onset),
  onset default 8), decoupled from band width. A leading edge's overflow
  clip is covered within travel ÷ onset of scroll, so content is never
  hard-clipped while the soft band is still easing open.
- Default travel lowered to sm (was md): clip coverage no longer depends
  on it, so it is purely cosmetic band-open speed.
- Rename the scroll-distance utility fade-ramp-* → fade-travel-* (theme
  --fade-travel-*, internal --tw-fade-travel[-active], keyframes
  tw-fade-travel-*). "ramp" read as a gradient/color ramp; "travel" names
  the scroll axis that distinguishes it from fade-size/fade-clear.
  MIGRATING maps fade-range-* → fade-travel-* directly (no ramp hop);
  the retired-token guard now bans the ramp token forms.
- Demo: rename the Travel slider + marketing copy; fix the chat-demo
  answer for "make the fade wider?" → fade-size (was travel, now inaccurate
  post-decouple).

Claude-Session: https://claude.ai/code/session_01B1Gn7DoGHbzGCLMbA72Stj
scripts/build-debug.mjs assembles a self-contained, gitignored
debug/index.html from scripts/debug/ sources, inlining the compiled
plugin CSS (same output dist/ ships) so the bench always reflects the
real engine.

Synchronized-scroll pressure test: every sample scroller is pinned to
the same offset, so any regression is a side-by-side visual diff. Covers
7 directions + ~16 real-world/edge cases + travel/onset/size/clear
sweeps, driving the engine via public custom props (no class explosion).
onset=1 reproduces the old coupled hard-clip (the A/B); the static-fallback
toggle mirrors the @supports-not path.

Claude-Session: https://claude.ai/code/session_01B1Gn7DoGHbzGCLMbA72Stj
- README: the prebuilt-CSS exclusion note listed "integer fade-size-*
  classes" — there is no integer fade-size form; fade-clear-* is the one
  with an integer scale. Corrected to fade-clear-*.
- README: --tw-fade-onset is documented as a public edge-speed knob under
  Travel Distance, but the public-surface note declared the entire
  --tw-fade-* namespace internal — a contradiction. Carve onset out as the
  documented exception.
- MIGRATING: note that the default travel changed md → sm (cosmetic, no
  action needed). It was documented only in the changelog.

Found by the 6-dimension pre-publish review; all minor/nit, no behavior change.

Claude-Session: https://claude.ai/code/session_01B1Gn7DoGHbzGCLMbA72Stj
Set the CHANGELOG 0.7.0 date to the actual publish date (the entry shipped
with a 2026-06-26 placeholder). dist/demo/version were already current at the
prior commit, so this carries only the date correction.

Claude-Session: https://claude.ai/code/session_01B1Gn7DoGHbzGCLMbA72Stj
@petekp
petekp merged commit 45a4b83 into main Jun 29, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant