Skip to content

Add scrolling primitives: contentOffsetX/contentOffsetY props and client/scroll size metrics - #988

Open
costajohnt wants to merge 5 commits into
vadimdemedes:masterfrom
costajohnt:scroll-primitives
Open

Add scrolling primitives: contentOffsetX/contentOffsetY props and client/scroll size metrics#988
costajohnt wants to merge 5 commits into
vadimdemedes:masterfrom
costajohnt:scroll-primitives

Conversation

@costajohnt

Copy link
Copy Markdown
Contributor

This implements the scrolling primitives sketched in #765, following the direction there: core primitives only, so a ScrollView can be built in userland (example included in the readme).

  • contentOffsetX / contentOffsetY props on Box. Children are shifted left/up by the given number of columns/rows at render time. Combined with overflow="hidden", this is the scroll mechanism. Layout is untouched, the offset is applied in renderNodeToOutput when recursing into children, so Yoga sees nothing new.
  • measureElement() now also returns clientWidth/clientHeight (size excluding borders) and scrollWidth/scrollHeight (content extent including overflow, computed from child layout extents and clamped to be at least the client size, matching DOM semantics). These extend the x/y/width/height shape from feat: extend measureElement() to return position coordinates #968.
  • useBoxMetrics() returns the same four new fields, so a userland ScrollView can be fully reactive to content changes via the existing layout listener.
  • The readme ScrollView recipe (and the runnable examples/scroll) wrap the content in a flexShrink={0} container. Without it, Yoga squeezes the children into the fixed-height viewport and there is nothing to scroll; the recipe notes this explicitly since it is the first thing anyone building a ScrollView will hit.

One deliberate divergence from the snippet in #765: child extents are measured relative to the inside of the container's border (parent border offsets are subtracted), so scrollWidth === clientWidth when content exactly fits a bordered box. The issue snippet measured against the outer edge, which over-reports the scroll extent by the border width.

Deliberately not included, per the discussion in #765: scrollbars, overflow indicators, an imperative scroll API, and any built-in ScrollView component. Offsets are also not clamped to the content extent, clamping policy belongs to the userland component (the readme example clamps via scrollHeight - clientHeight).

Tests: rendering tests for vertical/horizontal offsets, offsets inside borders, nested offset containers, offset beyond content, and a zero-offset behavior lock; metric tests for client/scroll sizes with overflowing content, borders, and content that grows after mount. All fail on master without the change (except the behavior lock). Verified manually in a real terminal with the included example (both axes, clamping at all edges).

Also relevant to #222.

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