ink: Support `Box` overflow and scrolling

Firstly: this library is amazing; I’m so excited to use it everywhere I possibly can. Sadly, this issue describes a use case that’s blocking me from moving forward 😦

I’m opening this issue and offering a corresponding Gitcoin bounty in hopes it will help. Thank you to anyone who can help make this happen!

Summary

This feature request seeks to cover the use case where a component may exceed the bounds of its container. Specifically, this issue seeks the following behaviors:

  • Allow <Box overflow={...}>, perhaps as implemented by #393
  • Allow Box components to scroll their contents. Based on my research, #393 alone is insufficient, since it doesn’t provide a way for a component to measure what its full width/height would be. (When overflow="hidden" is provided, width/height are measured based on the final component on-screen, and there seems to be no way around this)

Related

PR #393 (Add overflow prop to Box component) is mostly complete for my concerns here. I outlined my concerns with scrolling / measurements in this comment, but no idea what the right answer is.

https://github.com/vadimdemedes/goodness-squad/issues/5 describes a related use case (Fullscreen UIs). This issue doesn’t target fullscreen UIs specifically; overflow/scrolling behavior should work regardless of whether the component is going to be fullscreen or not.

Acceptance criteria

See comment below

Notes

Please let me know if the requirements could use clarification! I’m very keen to get this working 🙇

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 2
  • Comments: 26 (4 by maintainers)

Commits related to this issue

Most upvoted comments

I think it would be interesting to have that as a separate npm package, but I’m not sure I’d want to have that in Ink itself. If you have a complicated CLI that requires scrolling areas, you might be better of with ncurses-based alternative like blessed.

I think it would be interesting to have that as a separate npm package, but I’m not sure I’d want to have that in Ink itself.

@vadimdemedes I remember from my exploration into this issue that we can’t get a separate NPM package to work without a change to Ink’s rendering methods… since Ink is responsible for doing all the layout math, it needs to keep track of the “full size” dimensions as well as the computed dimensions on-screen (what I call “natural size” vs. “fixed size” above), but the problem is that there’s no way (right now) to create a react hook to report the natural size dimensions. It looks like this information gets lost somewhere deep inside the renderer (or worse, inside the Yoga/flexbox computations).

This stuff is all very confusing to me, however, since Yoga doesn’t (didn’t?) have good API documentation. Maybe I’m wrong.

Hi @gitcoinbot my code will be here https://replit.com/@codingsh/poc-ink-box-upgrade

@developerfred is this still current? It seems rather barebones, and it doesn’t currently even run at all (looks like you have a syntax error).


Anyway, I notice there is some movement on #412 and also I see #472 is new since I’ve spent effort investigating the state of this issue. @vadimdemedes could you please comment on what a path forward might look like? I’m fine if it is actually possible to achieve this “natural size” calculation in a separate NPM package, but I just don’t see how that’s possible.

If further coordination across existing PRs is necessary, I could potentially double the bounty and split it up across contributors/maintainers, since I really want this behavior, but mind you I’m only working with my personal funds here. But if this is a multi-person effort, I do want to recognize that and reward everyone’s efforts. This behavior is the only thing stopping me from using Ink for a number of projects of varying sizes, and I can’t move forward on those projects in a way that satisfies me (because, well, who wants to use blessed when ink exists 😉

I think it would be interesting to have that as a separate npm package, but I’m not sure I’d want to have that in Ink itself. If you have a complicated CLI that requires scrolling areas, you might be better of with ncurses-based alternative like blessed.

The issue with blessed and similar variants is we don’t get the declarative dom-like environment that we get here… as it stands and (please someone correct me if I’m wrong), Ink is the only project that makes building a CLI or TUI more or less like building for the web…

And I believe that’s hugely important because we’ve come to realize the terminal offers one of the most productive, distraction free environments in existence… a turn-key solution to scrolling is absolutely fundamental in my opinion. Thanks for listening

Awesome @developerfred, glad to hear about progress!

In the meantime, I grabbed the relevant stuff from my use case and made a repo for it at gnidan/ink-scroller. There’s something strange going on with left/right scrolling, but I’m less focused on that, since I just haven’t looked into it.

Point of that repo: I want to be able to stop scrolling at the end of the text 😃

Acceptance criteria

  • A1. Given component A of unknown “natural size” (xA, yA) inside parent component B of fixed size (xB, yB),

    • A1.1. A must render within the bounds of B with overflow hidden

    • A1.2. Either A or B must be able to compute A’s natural size (xA, yA), e.g. to ensure that A never completely leaves the viewport of B.

  • A2. Solutions must perform reasonably well without noticeable re-rendering or other flickering. This might mean fixing the flickering described in https://github.com/vadimdemedes/ink/issues/359, but not necessarily (since A1 paired with stdout measurement means it’d be trivial to prevent rendering something larger than the terminal).

  • A3. Solutions must work with existing components in the ecosystem, including ink-spinner, ink-select-input, ink-progress-bar, etc. This means one of two options:

    • A3 (option 1, strongly preferred). Solution is merged and released as part of this library’s official distribution channel. This means getting @vadimdemedes’s approval, but I don’t want to rely on that for this bounty.

    • A3 (option 2). Solution is releasable as a forked NPM package. Two stipulations:

      • A3(2).1. Changes are opened as PR here (so that I may seek to champion getting the changes into a main-line release once your work is done)

      • A3(2).2. Solution includes clear instructions on getting the above-mentioned component packages to work cleanly. Those packages use "ink" itself as a dependency in package.json, and that means ink-spinner (e.g.) will try to use the officially-released rendering logic as opposed to whatever modified version your solution provides. (I ran into this problem when I released #393 as a fork.) Solutions that require forking any/all component packages are not acceptable, and my use case doesn’t afford leveraging systems like yarn’s resolutions config. (I intend to use this work in a dependent application released to NPM and installable with npm install, so yarn-specific niceties are sadly just not going to cut it.)

  • A4. Solution includes automated tests and follows consistent style and quality alongside the rest of Ink’s codebase.

This is about the extent of what I can think of as necessary, but of course I understand that there may be ambiguity or technical limitations when it comes to the details. Please don’t hesitate to communicate any comments, questions, or concerns.

Thank you to everyone who has thus far applied to work on this bounty! I will continue reviewing each of your applications and will respond to each individually in the next 48 hours. ❤️

Thanks @gnidan, every dollar makes the Ukrainian victory closer 💛

Glad to see some activity on this issue. I’ll review the acceptance criteria and state of current efforts. I still want this, and I’m still willing to spend the listed bounty!

Thanks for your insight @vadimdemedes and @zach-is-my-name 🙏