feat: add single-corner radius modifiers and inset dock modifier - #244
Merged
Conversation
Contributor
📦 Snapshot releasePublished |
tenphi
force-pushed
the
feat-radius-corners-and-inset-stretch
branch
from
July 29, 2026 11:19
3a5e4ed to
a103255
Compare
Both cases previously had no expressible form, which forced authors into raw 4-value box syntax that other tooling then could not safely rewrite. radius: a directional modifier addresses the corner *pair* along an edge (`radius: 'top'` rounds top-left and top-right), so a single corner could not be expressed. An unrecognized corner name was silently dropped and the value applied to every corner — `radius: '4px top-left'` emitted `border-radius: 4px`. Add `top-left`, `top-right`, `bottom-right` and `bottom-left`, which set one corner, default to `var(--radius)` when no value is given, combine with edge modifiers, and work with `longhand` and CSS-wide keywords. inset: add a `dock` modifier that pins the named edge and spans its full length by also applying the value to the two perpendicular sides, so `inset: 'bottom dock'` gives `inset: auto 0 0 0`. The name follows the established UI-toolkit meaning (WPF/WinForms `Dock=Bottom`): attach to an edge and fill it. Properties opt in via a new `spanModifiers` field on DirectionalConfig; only inset sets it, so padding/margin/scrollMargin treat `dock` as an unknown modifier and are untouched. `dock` is parsed as a modifier natively, so no parser changes are needed. An earlier draft used `stretch`, which the parser classifies as a value keyword (it is meaningful for align-items and width) and which therefore required lifting the token back out of the value list. No behaviour change for previously valid input: 1746 tests pass, including the existing radius and inset suites. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The feature adds ~110 B to the static bundle, which had only 30 B of headroom against its 17 kB limit. Deduplicating the edge/corner logic into a single cornerIndices helper and deriving perpendicular sides by index arithmetic instead of a lookup object recovered most of it — main actually lands at 52.92 kB, and every other entry keeps its headroom — but static still needs 17.25 kB. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tenphi
force-pushed
the
feat-radius-corners-and-inset-stretch
branch
from
July 29, 2026 11:26
a103255 to
789bd1e
Compare
Merged
This was referenced Jul 29, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two shapes that currently have no expressible form in the DSL, which forces authors into raw 4-value box syntax. Found while auditing
cube-ui-kit—eslint-plugin-tastywanted to rewrite that raw syntax into directional shorthand and couldn't, because these two properties had no lossless target.radius: single-corner modifiersA directional modifier addresses the corner pair along an edge —
radius: 'top'rounds top-left and top-right — so a single corner had no representation.Worse, an unrecognized corner name was silently dropped and the value fell through to every corner:
Added
top-left,top-right,bottom-right,bottom-left:The value is optional and defaults to
var(--radius)(1r), matching how edge modifiers already behave. Corner modifiers combine with edge modifiers, work withlonghand, and accept CSS-wide keywords (radius: 'inherit top-right').The edge and corner loops are now one
applyCornerModshelper shared by the value path and the keyword path — previously the keyword path had its own copy of the corner-pair logic and would have needed the fix duplicated.inset:dockmodifierPins the named edge and spans its full length, applying the value to the two perpendicular sides:
The name follows the established UI-toolkit meaning — WPF/WinForms
Dock=Bottom, Qt dock widgets: attach to an edge and fill its length.Properties opt in via a new
spanModifiersfield onDirectionalConfig. Onlyinsetsets it, sopadding,marginandscrollMargintreatdockas an unknown modifier and are untouched (padding: '1x bottom dock'===padding: '1x bottom').On the name
An earlier draft of this PR used
stretch. That was the wrong choice:stretchis in the parser's globalVALUE_KEYWORDS(it's meaningful foralign-items,width, …), so it gets classified as a value, not a modifier —inset: 'bottom stretch'parses tovalues: ['stretch']and emitsinset: auto auto stretch auto. Supporting it meant an opt-in flag plus lifting the token back out of the value list.dockis parsed as a modifier natively, so that machinery is gone andDirectionalConfigjust gains a list of recognized span modifiers. I checked the alternatives through the parser —stretchwas the only candidate of ~16 that buckets as a value;fixed(already adimension.tsmodifier),fill(a tasty style name) andspan(a real CSS grid keyword) were ruled out for collisions.Note this means
inset: 'bottom stretch'still emits the invalidinset: auto auto stretch auto. That's pre-existing and untouched here — happy to reject or ignorestretchforinsetin a separate PR if you want it hardened.Reviewer notes
round,ellipse,leaf,backleaf),longhand, multi-group syntax and individual direction props all emit exactly what they did before. 1746 tests pass (+10 new),tsc,eslint,prettierclean.inset: '2x bottom dock'I applied the value to every side the modifier touches →auto 16px 16px 16px. The alternative reading is "pin 2x from the bottom, but span flush to the edges" →auto 0 16px 0. Both collapse to the same thing for the zero-value case, so the motivating example doesn't disambiguate. I picked the uniform reading for consistency with how values apply to named sides elsewhere — easy to flip.docs/styles.mdnow distinguishes edge from corner modifiers forradius(the old wording, "rounds only the specified corners", was what made the pair behaviour surprising), and documentsdock. Prop-type JSDoc updated for both, and'dock'added to theinsetunion.Follow-up
Once this lands,
eslint-plugin-tastycan stop excludingradiusandinsetfromprefer-directional-shorthand(excluded in #26 precisely because no lossless rewrite existed) and start suggesting these forms instead.🤖 Generated with Claude Code