Code Monkey home page Code Monkey logo

Comments (21)

sindresorhus avatar sindresorhus commented on May 12, 2024 4

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.

xdave avatar xdave commented on May 12, 2024

I think figuring this out would also solve the nested-div-newline problem.

from ink.

xdave avatar xdave commented on May 12, 2024

Whoa: https://github.com/iamdustan/react-hardware
Oh, this too: https://github.com/Yomguithereal/react-blessed

from ink.

marionebl avatar marionebl commented on May 12, 2024

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.

vadimdemedes avatar vadimdemedes commented on May 12, 2024

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.

karaggeorge avatar karaggeorge commented on May 12, 2024

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.

vadimdemedes avatar vadimdemedes commented on May 12, 2024

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 terminal
  • y - 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.

karaggeorge avatar karaggeorge commented on May 12, 2024

@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.

vadimdemedes avatar vadimdemedes commented on May 12, 2024

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.

karaggeorge avatar karaggeorge commented on May 12, 2024

@vadimdemedes

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.

vadimdemedes avatar vadimdemedes commented on May 12, 2024

Yes, I totally missed that, good catch.

from ink.

vadimdemedes avatar vadimdemedes commented on May 12, 2024

@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.

karaggeorge avatar karaggeorge commented on May 12, 2024

@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.

vadimdemedes avatar vadimdemedes commented on May 12, 2024

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.

karaggeorge avatar karaggeorge commented on May 12, 2024

@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.

vadimdemedes avatar vadimdemedes commented on May 12, 2024

@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.

marionebl avatar marionebl commented on May 12, 2024

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.

vadimdemedes avatar vadimdemedes commented on May 12, 2024

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.

danikaze avatar danikaze commented on May 12, 2024

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.

vadimdemedes avatar vadimdemedes commented on May 12, 2024

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.

samuela avatar samuela commented on May 12, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.