Skip to content

feat(enforce-logical): the block axis, and sizes on request (#215) - #223

Merged
sergioazoc merged 1 commit into
mainfrom
feat/logical-block-axis
Oct 9, 2026
Merged

sergioazoc merged 1 commit into
mainfrom
feat/logical-block-axis

Conversation

@sergioazoc

Copy link
Copy Markdown
Owner

Closes #215.

Summary

Tailwind 4.2 shipped logical utilities for the block axis and for sizing. enforce-logical only mapped the inline axis, so a converted project could reintroduce mt-4, top-0 or border-b without a report.

  • Block axis: mt/mb → mbs/mbe, pt/pb → pbs/pbe, scroll-m*/scroll-p*, top/bottom → inset-bs/inset-be, and border-t/border-b → border-bs/border-be. These follow direction, whose default 'both' has always meant both axes.
  • sizing: true (off by default): w/h and their min-/max- forms → inline/block, and size-* → inline-* block-*.
  • left/right → inset-s/inset-e with a design system on 4.2+. This is the canonical spelling, so enforce-canonical no longer needs a second pass.
  • Never a dead class:
    • A 4.2 target is probed as <to>-0. Two shortcuts failed: isValid accepts an arbitrary value on any prefix, so mt-[3px] became mbs-[3px] on 4.1, and inline-flex made inline look like a known prefix.
    • Without a design system, the block axis and sizes are only suggested.
    • A named size converts only when both classes declare the same value (w-xs reads --width-xs, while inline-xs reads --container-xs).
    • w-dvh, h-dvw, max-w-prose and max-w-screen-* have no counterpart and are skipped.
  • New messageId useLogicalWritingMode for the block axis and sizes. These differ from their logical forms only in vertical text, not in RTL.
  • enforce-physical inverts all of the above and never touches a display utility (inline-flex).
  • enforce-shorthand folds the logical pairs, so logical + shorthand converge whichever fix lands first.

Bench

  • On shadcn/ui apps/v4, enforce-logical goes from 600 → 1160 reports, all on the block axis. 138 messages now name inset-s/inset-e, and nothing is removed.
  • The CSS oracle finds all 1028 fixed strings equivalent.
  • The baselines, latest.json, /benchmark and /comparison are regenerated.

Test plan

  • Table-generated cases with and without a design system; sizing across theme namespaces; a hand-built Tailwind 4.1 design system for convertDirectional; display exclusion.
  • Mutations of the value comparison, the 4.1 probe, skipValues and the display exclusion each fail a test.
  • New e2e logical-shorthand-convergence: real binary, every fix order converges. Removing the mbs+mbe family fails it.
  • engine-smoke.mjs on real Tailwind 4.1.15 (left-[3px] → start-[3px], no mbs-) and 4.3.3. CI runs 4.1.15 and 4.2.
  • Docs (EN/ES): mapping table, direction, sizing, the behavior without a DS and on 4.1, interactions; doc-examples runs every new ✗/✓ example.
  • Lint, lint:types, format:check, typecheck, build and pnpm test (3704 + 312); bench npm test; interop.mjs.

🤖 Generated with Claude Code

https://claude.ai/code/session_019vTh6S5A41M1HLkmk3FaM1

Tailwind 4.2 shipped logical utilities for the block axis and for sizing, and
enforce-logical only mapped the inline axis, so a converted project could
reintroduce `mt-4`, `top-0` or `border-b` unreported.

- Block axis: mt/mb → mbs/mbe, pt/pb → pbs/pbe, scroll-mt… → scroll-mbs…,
  top/bottom → inset-bs/inset-be, border-t/border-b → border-bs/border-be.
  They follow `direction`, whose default 'both' always meant both axes.
- `sizing: true` (off by default): w/min-w/max-w → inline/min-inline/
  max-inline, h/… → block/…, size → inline + block (variant and `!` on both).
- With a design system on 4.2+, left/right become inset-s/inset-e, the
  spelling enforce-canonical would rewrite start/end into.
- Never a dead class. A 4.2 target is probed as `<to>-0` (isValid accepts an
  arbitrary value on any prefix, so `mt-[3px]` became `mbs-[3px]` on 4.1;
  `inline-flex` made `inline` a known prefix). Without a design system the
  block axis and sizes are only suggested, through reportClassSuggestion, and
  left/right fall back to start/end. A named size converts only when both
  classes declare the same value (`w-xs` reads --width-xs, `inline-xs` only
  --container-xs); `w-dvh`, `h-dvw`, `max-w-prose`, `max-w-screen-*` have no
  counterpart and are skipped.
- New messageId `useLogicalWritingMode` ("so it follows the writing mode") for
  the block axis and sizes; ReplacementEntry takes a per-entry messageId so one
  string can mix them under one autofix.
- enforce-physical inverts all of it, both inset spellings included
  (LOGICAL_INSET_ALIASES folded into invertAxisMappings), and never touches a
  display utility.
- enforce-shorthand folds the logical pairs (mbs+mbe → my, inset-s+inset-e →
  inset-x, border-bs+border-be → border-y, the four logical sides), so logical
  + shorthand converge whichever fix lands first; never inline+block → size.
  declaredValues/sameValues move to utils/declared-values.ts, shared.

Tests: generated table cases with and without a design system, sizing across
theme namespaces (axis-namespaces.css gains --width-xs), a hand-built 4.1
design system for convertDirectional, display exclusion, a real-binary e2e for
convergence in every fix order, and engine-smoke on the real 4.1.15 / 4.2.
Mutations of the value comparison, the 4.1 probe, skipValues and the display
exclusion each fail a test.

Bench: enforce-logical on shadcn/ui apps/v4 goes 600 → 1160 (block axis);
138 messages now name inset-s/inset-e; nothing removed. The CSS oracle finds
all 1028 fixed strings equivalent. Baselines, latest.json, /benchmark and
/comparison regenerated.

Claude-Session: https://claude.ai/code/session_019vTh6S5A41M1HLkmk3FaM1
@sergioazoc
sergioazoc merged commit a060a90 into main Oct 9, 2026
13 checks passed
@sergioazoc
sergioazoc deleted the feat/logical-block-axis branch October 9, 2026 00:59
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.

enforce-logical: map the block axis and sizing (Tailwind 4.2 logical utilities)

1 participant