Comments (21)
Yoga has an asm.js build for browsers, which we could use in Node.js to not need a native dependency: https://github.com/facebook/yoga#build-platforms
from ink.
I think figuring this out would also solve the nested-div-newline problem.
from ink.
Whoa: https://github.com/iamdustan/react-hardware
Oh, this too: https://github.com/Yomguithereal/react-blessed
from ink.
Perhaps this is overcomplicating things, but introducing a View
using yoga-layout
could solve this by introducing a full layout engine. I am not quite sure how one would go about building this. Reading and understanding the code of projects using yoga-layout
should help, though:
- react-vr
- react-pdf
- react-sketchapp
Is this something you'd be interested in?
from ink.
I think this is definitely interesting, but might be an overkill for now. I still hope there will be a simple solution to that issue.
from ink.
I'd like to give this one a try. What exactly are we looking for? Should it be that every element past the first one should render in less space than the entire terminal based on the previous elements?
Should that happen for elements in a div
? or in general?
Also, would it make sense to automatically cut anything that goes over the terminal length for each line (instead of creating another line)? Or just let the developer take care of making sure all lines are shorter than the total available space?
from ink.
I'd like to give this one a try. What exactly are we looking for? Should it be that every element past the first one should render in less space than the entire terminal based on the previous elements?
I thought each component would have access to these props:
x
- distance from the left side of terminaly
- distance from the first row of output
I think exposing these props would allow components to calculate the available space in the current row. Ink would also have to rerender the tree whenever terminal is resized. This is ideal implementation, but might be complex to implement.
Should that happen for elements in a div? or in general?
I think all elements should have access to these props.
Also, would it make sense to automatically cut anything that goes over the terminal length for each line (instead of creating another line)? Or just let the developer take care of making sure all lines are shorter than the total available space?
I think given the props above, developer should decide themselves whether to cut the output or not.
I just had an idea to perhaps simplify the first implementation and experiment:
<SpaceAware>
<SpaceAware.Item>
<Color red>Progress: </Color>
</SpaceAware.Item>
<SpaceAware.Item>
{({ spaceAvailable }) => (
<ProgressBar width={spaceAvailable} value={0.5}/>
)}
</SpaceAware.Item>
</SpaceAware>
Naming isn't final of course, but the idea is this: SpaceAware
renders to string via renderToString()
each SpaceAware.Item
child and calculates spaceAvailable
for each of those and pass it down via render function. I realize it's not the prettiest implementation, but it's a start and could serve as a temporary solution until the "complete" system of x
and y
coordinates is implemented.
@karaggeorge @sindresorhus What do you think?
from ink.
@vadimdemedes I'm a bit confused with the x
and y
system. How can a component (like ProgressBar) calculate how wide it has to be just using the proposed x
and y
. I think maybe a left
and right
type of prop my help more. left
being the x
and right
being the maximum space left for the component to take on the terminal. Actually, that would make more sense if only the right-most component received the right
.
It might be also weird to use renderToString()
to calculate the size, but the components will need these new props to render in the first place.
The x
and y
as described would actually help a lot if we want to only update a specific component that updated instead of the whole tree.
Another idea might be having the components pass a flex: true
prop in a surrounding component which would then pass the available size left on the screen to its child after all non-flex components have been rendered. If more than one flex
components exist in one line, they would split the space between them. Thoughts?
from ink.
I'm a bit confused with the x and y system. How can a component (like ProgressBar) calculate how wide it has to be just using the proposed x and y.
You can get the available space using terminal width - x = available width
. The y
coordinate is for placing mouse cursor, you can ignore it for this example.
I think having a flex
prop would be complicated to explain and use.
Let me play with my idea and see if it even works. I'll submit it as a PR and ping you.
from ink.
You can get the available space using terminal width - x = available width
that would be true only if the component is the last one on the line, right?
from ink.
Yes, I totally missed that, good catch.
from ink.
@karaggeorge I implemented my idea but indeed is limited to 2 components on one row, side by side. I rethinked your idea with flex and I think it's the best way to solve this. My idea is to implement an alternative of CSS flexbox in Ink. That way layout is clearly determined and straightforward to understand. My thoughts:
// Progress: [======] (ProgressBar takes all the available space)
<Box>
<Box>
Progress:
</Box>
<Box flex={1}>
<ProgressBar/>
</Box>
<Box>
15%
</Box>
</Box>
<Box height={20} alignItems="center" justifyContent="center">
<HelloWorld/>
</Box>
It's indeed going to be a basic reimplementation of CSS flexbox, but using rows and columns instead of px.
from ink.
@vadimdemedes Yeah, CSS flexbox is where I got that idea. I think it would make sense in this case, and it solves a couple of problems. What are you thinking about a full set of props? I was thinking just the flex-grow
, but I see you incorporated more of them.
I'm wondering about the height. How would that display with the children of that element? Would it be a new line before and after the box? Like a div with a set height?
from ink.
What are you thinking about a full set of props?
I think we should start with the minimum set first and expand over time.
I'm wondering about the height. How would that display with the children of that element? Would it be a new line before and after the box? Like a div with a set height?
Exactly 🙂
from ink.
@vadimdemedes
I think that makes sense. I'll start working on PR. Do we want it to be a prop passed in to any component? Or do we want to have a wrapper that does it for the children? The way you had it before:
<SpaceAware>
<A/>
</SpaceAware>
or <Flex/>
as a wrapper, which would lead to A
receiving an availableSpace
prop.
from ink.
@karaggeorge Sorry for late response. I thought we could go with #5 (comment) to provide a complete layout solution. I tried implementing <SpaceAware>
and it looks more like a hack than a solution.
from ink.
It's indeed going to be a basic reimplementation of CSS flexbox, but using rows and columns instead of px.
@vadimdemedes Does it make sense to explore yoga-layout
to do this?
from ink.
Yoga is built with cross platform in mind. To ensure Yoga can be used anywhere, it was written in portable C/C++ and has a low number of dependencies and small binary size. This means Yoga can be used on iOS and Android, sharing knowledge, and potentially code, between platforms.
@marionebl I guess this means that Ink will have to include a native dependency, which I'd like to avoid.
from ink.
I tried to implement something similar.
Just a simple <AppTitle>
component, which renders a colored bar with the centered title.
The problem is that Box
doesn't render bgColor so I need to do something like this:
export function AppTitle(props: Props) {
const text = props.children;
const width = props.width;
const middle = Math.floor((width - text.length)/ 2) + text.length;
return (
<Color bgBlue white bold>
{text.padStart(middle, ' ').padEnd(width, ' ')}
</Color>
);
}
Works like a charm. width
is passed as a prop (which I think I could automatically read from stdout
via process
or <StdoutContext>
, but I'm getting it from redux state so the component it's re-rendered when the window is resized.
But there's a problem (of course), and it's that the component is rendered multiple times instead of being replaced (probably a different issue #153 ?)
from ink.
Going to close this issue, as there's a <Box flexGrow={1}>
component which will fill all available space and #168 is going to introduce an API to measure <Box>
width.
from ink.
I'm curious how this is implemented under the hood: How does ink get the number of rows/cols for the current tty, and detect when that changes?
I'm currently interested in serving Ink sessions over a custom SSH server. The SSH protocol gives the the rows/cols of the user's terminal, but it's not clear to me how to pass these values to Ink's render
. Can Ink accomplish something like this?
from ink.
Related Issues (20)
- Render Output to Calling Function
- CI is currently broken
- Github CI Pipeline fails when using bold text using vitest snapshot tests HOT 1
- RFE: expose index of output line in Transform HOT 1
- This project is dumb HOT 1
- "space-evenly" value is missing for justifyContent property of the Box Component HOT 5
- SyntaxError: Unexpected token '<' HOT 1
- Addition of `@alcalzone/ansi-tokenize` is a breaking change as it only supports Node 16+ HOT 5
- Please fix the issue that TS can't find ink's types HOT 1
- ReferenceError: self is not defined with DEV=true and ESM
- Ink 4.4.0 doesn't wait for user input from `stdin` on second mount HOT 15
- ink 4.4.x breaks text input tests HOT 1
- mouse click hook HOT 2
- Ignore OSC ansi sequences when calculating line length HOT 2
- Ink 4.4.x incorrectly detects backspace HOT 2
- Bun support HOT 2
- Friendly request to include tailwind-ink in the README HOT 1
- Just wondering
- Is there an example of showing QR code? HOT 1
- Dead Demo links in README
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ink.