Skip to content

feat: Add UseComponentRect#145

Open
barsoosayque wants to merge 5 commits intoccbrown:mainfrom
barsoosayque:use-rect
Open

feat: Add UseComponentRect#145
barsoosayque wants to merge 5 commits intoccbrown:mainfrom
barsoosayque:use-rect

Conversation

@barsoosayque
Copy link
Contributor

@barsoosayque barsoosayque commented Oct 11, 2025

What It Does

Add a new UseComponentRect with hooks.use_component_rect(). Works similar to use_terminal_size, but for the current component: returns component's rect from the previous rendering or None for the first rendering.

Related Issues

@codecov
Copy link

codecov bot commented Oct 11, 2025

Codecov Report

❌ Patch coverage is 95.23810% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.05%. Comparing base (48518db) to head (18a302c).

Files with missing lines Patch % Lines
packages/iocraft/src/hooks/use_component_rect.rs 95.23% 1 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #145      +/-   ##
==========================================
+ Coverage   89.74%   90.05%   +0.31%     
==========================================
  Files          31       32       +1     
  Lines        5139     5181      +42     
  Branches     5139     5181      +42     
==========================================
+ Hits         4612     4666      +54     
+ Misses        427      414      -13     
- Partials      100      101       +1     
Files with missing lines Coverage Δ
packages/iocraft/src/hooks/use_component_rect.rs 95.23% <95.23%> (ø)

... and 1 file with indirect coverage changes

Impacted file tree graph

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ccbrown
Copy link
Owner

ccbrown commented Oct 11, 2025

Thanks for the PR! I think there is a potential pitfall here:

On the first pass, the returned rect will be (0,0,0,0), and additional passes aren't triggered automatically, so I think there are a few ways users might unexpectedly not get any actual values out of this.

Knowing the dimensions on the first pass is impossible, and automatically triggering additional passes when the rect changes might introduce another pitfall – an easy way to create infinite/busy rendering loops depending on how the rect is used.

A step forward might be to emphasize in the documentation that this hook provides the rect for the previous pass, if there was one. However, there's still a shortcoming of the hook:

let r: Rect = hooks.use_component_rect();

hooks.use_terminal_events(move |event| {
    // If you use `r` here, it might not be the correct rectangle for the most recent render!
    // For example, if only one render pass has been done, `r` will be (0, 0, 0, 0).
});

To allow closures to reliably get the value for the latest render pass, a reference type, maybe leveraging the new UseRef API, might be better. So maybe this looks like...

let r: Ref<Rect> = hooks.use_component_rect();

hooks.use_terminal_events(move |event| {
    // `r.get()` is always the up-to-date value here!
});

@ccbrown ccbrown added the enhancement New feature or request label Oct 11, 2025
@barsoosayque
Copy link
Contributor Author

I think I got it ? I'm not sure I used the new Ref properly, but it seems to work in my tests. It's sad that I can only use it after the first render, because for my ProgressBar I couldn't render it with the proper width right away, I would still have to do the overflow trick (which is not that bad honestly).

@ccbrown
Copy link
Owner

ccbrown commented Oct 12, 2025

Yep, this looks like it'll do the trick! I'm going to leave this open for a bit though and see if any better ideas for approaching this problem come to me.

Of course in the meantime, anyone reading this can copy/paste the hook into your own codebase if needed.

@bram209
Copy link

bram209 commented Oct 14, 2025

Since it returns the position / size from the render of the previous frame, would it not be better to be explicit about that and return Option<Rect>, returning None if there is no previous frame, instead?

@barsoosayque
Copy link
Contributor Author

Since it returns the position / size from the render of the previous frame, would it not be better to be explicit about that and return Option, returning None if there is no previous frame, instead?

That's a good idea. I rewrote it to return Option<Rect>, and also re-render if Option::None changed to Option::Some

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants