-
Notifications
You must be signed in to change notification settings - Fork 77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor(accordion, accordion-item): getElementProp
on child is factored out and parent gets a mutation observer to update children
#6055
Conversation
…ut and parent gets a mutation observer to update children
…ementProp-and-get-mutation-observer-on-parent
I implemented this new pattern to just the Or I can put all other properties that need to be inherited in this PR as well since most of the work is done. I would just need to know which additional ones need to be inherited ( Added "[Erik/Eliza]: Pattern Discussion: Parent <> Child Property Relationships" for the next meeting. |
getElementProp
on child is factored out and parent gets a mutation observer to update children
getElementProp
on child is factored out and parent gets a mutation observer to update childrengetElementProp
on child is factored out and parent gets a mutation observer to update children
|
||
private passPropsToAccordionItems = (): void => { | ||
( | ||
Array.from( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use the existing this.items
instead of querying for the child items again? I suppose this.items
may not always be populated at connectedCallback
but should be in componentDidLoad
componentDidLoad(): void {
...
this.passPropsToAccordionItems();
}
and
private passPropsToAccordionItems = (): void => {
this.items.forEach((el) => (el.scale = this.scale));
};
Seems to work reliably.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes sense as long as this.items
gets updated when accordion-item
s get added or removed from the light dom. Is this currently handled in any way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah good point the internal registration events are kind of an outdated pattern and wouldn't respond - slot change observer that responds to addition / removal of children and updates this.items
is probably better. There's a handful of our ... more senior 👴👵 ... components that could probably benefit from a change like that.
await page.waitForChanges(); | ||
|
||
expect(await accordion.getProperty("scale")).toEqual(scale.l); | ||
expect(await item1.getProperty("scale")).toEqual(scale.m); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we want the scale of calcite-accordion
and calcite-accordion-item
to match in this case - shouldn't let folks set scale "m" on the child if the parent is "l". (assuming scale on calcite-accordion-item
is internal property)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems logical that if calcite-accordion-item is an internal property we shouldn't be letting users set it to a different scale, but based on other comments looks like this is also part of tomorrow's Child Property Relationships discussion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we want the scale of
calcite-accordion
andcalcite-accordion-item
to match in this case - shouldn't let folks set scale "m" on the child if the parent is "l". (assuming scale oncalcite-accordion-item
is internal property)
I agree it seems odd to allow this, but if you think about it, this pattern breaks component autonomy. When a component defines its own scale
prop, I as a developer expect it to honor whatever value I'm explicitly setting it to, excepting the default fallback value. If a parent value comes in and overrides that value I've explicitly set on the child, the property pattern on that child component no longer behaves according to standard convention.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, although if the property is internal and is set by / managed by the parent maybe I wouldn't expect to be able to set this at all, as its undocumented. Though to follow through on that the scale probably shouldn't have the default to "m" until it receives the scale from calcite-accordion
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This same principle applies to object inheritance in programming. If I have Object A that defines a foo
property, an Object B that extends Object A, I don't expect setting the foo
property on Object A to override what I've explicitly set it to on Object B. I expect the lowest level of specificity on that property to win above all others.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right - but its not a public property (or, is proposed to be an undocumented, internal property) - so the test case of it being set in that way should not be valid?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, although if the property is internal and is set by / managed by the parent maybe I wouldn't expect to be able to set this at all, as its undocumented. Though to follow through on that the scale probably shouldn't have the default to "m" until it receives the scale from
calcite-accordion
.
For sure. I think with a component like accordion
, its children items are so tightly interwoven with the parent that this pattern does make sense where you would explicitly control children properties like scale
from the parent level. It gets trickier when you have child components that can live standalone by themselves like radio-button
and tile-select
where they need to work on their own regardless if their corresponding parent wrapper component is being used.
Right - but its not a public property (or, is proposed to not be an undocumented, internal property) - so the test case of it being set in that way should not be valid?
Agreed. I think if we mark these properties as internal, and call out in our documentation that modifying internal properties is not supported, then this pattern can be adopted for certain parent/child component systems.
expect(await item1.getProperty("scale")).toEqual(scale.s); | ||
|
||
const icon1: E2EElement = await page.find(`calcite-accordion-item[id='1'] >>> .${CSS.iconStart}`); | ||
expect(await icon1.getProperty("scale")).toEqual(scale.m); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we instead expect this icon be a scale s
based on the scale s
of the parent calcite-accordion-item
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably add this to tomorrow's Pattern Discussion: Parent <> Child Property Relationships. From what I understand while we expect a parent to update children where these 2 have a parent/child relationship (as in accordion and its item), element and its slotted icon don't have that relationship and are expected to have independent scales. But in this particular case, it does feel a bit odd. Erik also brought up that we should not override an item with the parent if a user sets it individually to a different scale, although I'm not sure what the use case for that would be.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Erik also brought up that we should not override an item with the parent if a user sets it individually to a different scale, although I'm not sure what the use case for that would be.
Not sure what the specific use case would be either, but I still think that if the scale
property is explicitly applied either as an attribute or by setting the property directly on the child component, that this value should be honored and not overridden by the parent component. We can actively discourage doing this in the documentation, and encourage users to set the value at the parent level to ensure visual consistency, but I don't think we should break from convention with regards to how property values are honored at the individual component level.
This PR has been automatically marked as stale because it has not had recent activity. Please close your PR if it is no longer relevant. Thank you for your contributions. |
Closing this, as it was resolved in #7191. |
Related Issue: #6038, #5698
Summary
getElementProp
on child is factored out and parent gets a mutation observer to update children.