Closed ajlende closed 6 years ago
Have you tried using the terra-responsive-element to toggle the list vs table item markdown? That is what currently managing which layout should be rendered.
@emilyrohrbough I came across this when copying code from Kaiju and turning the various pieces into components. The problem for me isn't so much that I can't create a component, but it's more that I would expect copying code in-verbatim into a component to "just work". Instead I get this error and couldn't find any documentation explaining why I can't wrap the component.
Hi @ajlende
My assumption is you need to allow properties to pass through your component wrapper onto the Item. The ItemCollection clones each Item and copies special props into them. Try opening up your custom component to accept properties.
const MyCustomItem = (props) => (
<ItemCollection.Item {...props}>
<ItemCollection.Display text="Custom Display" />
<ItemCollection.Display text="Another Display" />
</ItemCollection.Item>
);
There are a few additional thoughts I wanted to add here to address why copying code into a custom component does not always work.
It's important to note that creating custom component wrappers can break API contracts.
As demonstrated in your example, removal of the property spread resulted in a malformed component structure and functionality.
The other common contract broken with custom components is type checking. If the ItemCollection needed to ask the child its type it would return MyCustomItem
and not ItemCollection.Item
// This logic statement would fail if a component wrapper was used
if(child.type === 'ItemCollection.Item`) {
// ...
}
For this specific case of the item collection I don't see any immediate issues resulting from creating a custom component. But it should be done with caution and with a thorough understanding of possible side effects.
It is very possible that in the future the ItemCollection may need to perform type checking on its children.
@StephenEsser What you said makes sense. This is more of a documentation issue than anything else, I'd say. Exactly what ItemCollection
and ItemCollection.Item
are doing (and what they are expecting) isn't clear from just reading the documentation and examples.
@ajlende would you want to open a PR to beef up the documentation so they are a bit clearer?
@emilyrohrbough I can do that when I have some time. Might be a bit before I can get to it.
@ajlende
This is somewhat of a challenging dilemma regarding documentation. In my opinion this is not a direct issue with the ItemCollection documentation but a generic expectation of all components that have subcomponents.
There is an implied expectation that certain components are expecting certain children. Passing in unexpected content challenges the API contract.
A List component is expecting List Items A Table component expects Rows, Columns, and Cells A Select component expects Options
These expectations also apply to native html
<select>
<option />
</select>
<ul>
<li />
</ul>
There are dozens of more examples throughout the Terra ecosystem.
I don't know whether or not explicitly documenting that each of these components is expecting specific children is sustainable or appropriate to display in the terra site pages, but I do think there is some value in documenting at a high level the general overview of sub components.
Let me know what your thoughts are and any possible solutions you may have that might help solve this confusion for other components as well.
If you're just trying to encapsulate some of your component creation, you could forgo creating a separate wrapping component and simply use functions to avoid those problems:
import React from 'react';
import ItemCollection from 'terra-clinical-item-collection';
const buildCustomItem = () => (
<ItemCollection.Item>
<ItemCollection.Display text="Custom Display" />
<ItemCollection.Display text="Another Display" />
</ItemCollection.Item>
);
const App = () => (
<ItemCollection numberOfDisplays={2}>
{buildCustomItem()}
</ItemCollection>
);
export default App;
This simplicity breaks down quick if you need hooks into the lifecycles and whatnot, but I agree with Stephen in that I don't think more documentation will solve the problem completely. While we do our best to maintain consistency with our consumer-facing prop APIs, sometimes that forces us into a variety of internal implementation strategies that will have myriad impacts on things like wrapping/cloning/general manipulation of components passed in as props.
I do think that that updating the List/Table/etc. docs to say "The List will only support List.Item components as children" would be beneficial and might have saved you some time. I just think anything else would be hard to maintain and more than likely confusing to all but the most experienced consumers.
@StephenEsser Thanks for pointing out that this probably isn't limited to just ItemCollection
. If there are other Components that require specific children, then it might be worth adding a section to all Components with a requirement like that. MDN documentation has a section called "Permitted Content" on HTML Elements to show which Elements are allowed within an HTML Element (for example, ul
)—doing something similar in the Terra docs seems like a reasonable solution to me.
Additionally, if the Terra team wants to be more strict about which children are allowed, you could always add a custom prop-types check and throw an error when there is an unacceptable child. 🤷♂️
And @tbiethman, your example is basically what I landed on—just inside an Array.map
😄
Bug Report
Description
I wanted to create a custom item component for the item collection, but wrapping the
<ItemCollection.Item />
component results in incorrect HTML being generated (<li />
instead of<tr />
).The workaround of just inlining the component is straightforward, but I didn't expect wrapping the item in a component to break the code.
The example below is stripped down, but with a more complex item, it would be nice to break the item out into its own component for readability, if possible.
Steps to Reproduce
Short, Self Contained, Correct (Compilable), Example (produces incorrect results)
Workaround (produces correct results)
Additional Context / Screenshots
Error Message
Generated HTML
Expected Behavior
Expected HTML
Possible Solution
Environment
terra-clinical-item-collection@3.16.0