For example, a component like this currently renders all of the items on a single line. Like HTML makes the div have a block-level display (implicitly has a 100% width), perhaps ink's could do something similar?
const Things = ({ things }) => (
<div>
{things.map(item => (
<div>
<Indent size={2} indent={' '}>{item.text}</Indent>
</div>
))}
</div>
);
I like this idea, good point!
So I took a stab at implementing this and faced an interesting issue.
To take your example with removed indent code:
const Things = ({ things }) => (
<div>
{things.map(item => (
<div>
{item.text}
</div>
))}
</div>
);
You'd expect the following output in HTML:
A\n
B\n
But if I naively modify <div> in Ink to append \n after children, this is what you get:
A\n
B\n
\n
Notice the extra \n at the end, caused by the root <div>.
So in next step I decided to skip multiple consecutive \ns caused by stacking <div>s. So the example above wouldn't append that last \n. Basically how it works is <div> component checks its last child and if it's not a <div>, it appends a newline.
In case you'd want <div> to always skip the newline, there's an inline prop: <div inline>.
The example below appends only one newline:
<div>
<div>
<div>
Hello
</div>
</div>
</div>
Output: Hello\n.
Now, the problem can be demonstrated here:
<div>
Hello
<div>
<div>
World
</div>
</div>
</div>
Output: HelloWorld\n.
Notice that there are no newlines between Hello and World, which would happen in HTML.
Basically, this trick creates more inconsistencies than benefits. I think we should eliminate the black magic and resort to good defaults and leave the decisions to the developer:
<div> always appends a newline after children<div inline> skips the newlineIn my opinion, this will also make the output consistent with the expectations. I tried rewriting emoj for the new <div> logic and got lost with why there are newlines here and there.
As a meta comment, given you are not actually constructing HTML here, you'd be better off taking the React Native approach of using View instead of div. then your textual output is just another rendering engine, rather than being confused with ReactDOM, which treats all lower case components as pass through dumb items to render
@shaneosullivan good point.
@vadimdemedes <div inline> breaks the react typescript typings that I was using with this:
Type '{ inline: true; }' has no properties in common with type 'HTMLProps<HTMLDivElement>'.
:P
For the inline stuff, if you went the React Native route, it'd just be a Text component. All nice, clear and simple :-)
@shaneosullivan <div> is a component too. I just made it "invisible" to the user, so that they don't need to keep importing it in every file where it's used.
@xdave But I imagine Ink would have its own bindings, right? So that error is temporary.
Not sure how to augment the React.HTMLAttributes interface properly...... yet.
@sindresorhus what do you think about the <div> and <div inline> proposal?
If you're going to imitate HTML, it should be <div> and <span>.
This is probably going to be the right way to go.
@xdave Your TS bindings would also work with this approach, I assume.
Pushed https://github.com/vadimdemedes/ink/commit/376dc3a0ea3a910e12b3467c3e02619c6ea667c1 to make <div> insert \n after children. <span> now acts as a noop component to group elements.
Going to close this issue when a new release is out.
Landed in 0.3.0, thanks everyone!
Most helpful comment
As a meta comment, given you are not actually constructing HTML here, you'd be better off taking the React Native approach of using View instead of div. then your textual output is just another rendering engine, rather than being confused with ReactDOM, which treats all lower case components as pass through dumb items to render