Skip to content
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

feat(ProgressIndicator): add animation #9340

Conversation

kristastarr
Copy link

@kristastarr kristastarr commented Jul 27, 2021

Closes #9156

Progress Indicator Animations:

  • The blue line at the top of a completed step animates from left to right.
  • The "current" and "completed" status icons transition in opacity when they appear and disappear.
  • There is a subtle transition on the optional label text on initial page load.

Changelog

New
Added keyframes and transitions to _progress-indicator.scss

Changed
Changed the ProgressIndicator component in the React package - this change would require a StepData object to be passed in as a prop to the ProgressIndicator component, in order ProgressIndicator to render a ProgressStep. (Currently the ProgressSteps are being rendered as React.Children in ProgressIndicator).

Rationale: Properties of this.props.children cannot be modified, so currently are being re-rendered using React.cloneElement with the updated "current" or "completed" property each time the CurrentIndex changed. When I added the CSS for the animations, this caused all the icons to animate every single time there is a change to the status of any single ProgressStep. Rendering ProgressStep components from inside the ProgressIndicator enabled me to modify the "current" and "completed" properties of each ProgressStep to trigger a re-render of a step/icon only when there is a change to that specific ProgressStep.

Testing / Reviewing

You can see the changes by running the Carbon React Storybook.

recheck

@kristastarr kristastarr requested a review from a team as a code owner July 27, 2021 23:15
@netlify
Copy link

netlify bot commented Jul 27, 2021

✔️ Deploy Preview for carbon-react-next ready!

🔨 Explore the source changes: 483982a

🔍 Inspect the deploy log: https://app.netlify.com/sites/carbon-react-next/deploys/616f23ad155fd60008b1729a

😎 Browse the preview: https://deploy-preview-9340--carbon-react-next.netlify.app

@github-actions
Copy link
Contributor

github-actions bot commented Jul 27, 2021

DCO Assistant Lite bot All contributors have signed the DCO.

@kristastarr kristastarr marked this pull request as draft July 27, 2021 23:18
@kristastarr
Copy link
Author

I have read the DCO document and I hereby sign the DCO.

@netlify
Copy link

netlify bot commented Jul 27, 2021

✔️ Deploy Preview for carbon-elements ready!

🔨 Explore the source changes: 483982a

🔍 Inspect the deploy log: https://app.netlify.com/sites/carbon-elements/deploys/616f23ad4c35f10007e3f330

😎 Browse the preview: https://deploy-preview-9340--carbon-elements.netlify.app

@netlify
Copy link

netlify bot commented Jul 27, 2021

✔️ Deploy Preview for carbon-components-react ready!
Built without sensitive environment variables

🔨 Explore the source changes: 483982a

🔍 Inspect the deploy log: https://app.netlify.com/sites/carbon-components-react/deploys/616f23add63e4800084102bf

😎 Browse the preview: https://deploy-preview-9340--carbon-components-react.netlify.app

@johnbister
Copy link
Contributor

johnbister commented Aug 9, 2021

The motion looks great to me @kristastarr ! Do you think we should include what errors and disabled states would look like in this pattern as well? For instance, if the user cannot click ahead a few steps because prior steps determine what is displayed in subsequent steps. There was a great discussion with @lisajkaiser about this last week and I think it would be great to include these scenarios as well.

@kristastarr
Copy link
Author

@johnbister Yes, that makes sense! I'll work on adding the error and disabled states this week.

@johnbister johnbister mentioned this pull request Aug 10, 2021
55 tasks
@kristastarr kristastarr changed the title Progress tracker motion feat(ProgressIndicator): add animation Aug 11, 2021
@kristastarr kristastarr marked this pull request as ready for review August 26, 2021 17:30
Copy link
Contributor

@joshblack joshblack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The animation looks slick! I think the only big note from the implementation is that it seems like the PR makes a change to ProgressIndicator where it reverts it to a class component versus the function component that we refactored it to recently.

From a motion perspective, will we need to add in support for disabling this animation when the user has a no motion preference? 👀

@kristastarr
Copy link
Author

@joshblack Absolutely, I added media queries to disable the animations for users who prefer reduced motion.

@kristastarr
Copy link
Author

@joshblack I made the following updates:

  1. Resolved prior merge conflicts
  2. Updated css to use Carbon motion duration tokens
  3. Removed unnecessary props from ProgressStep that were causing console warnings

One thing to mention (which maybe I should have indicated elsewhere?) is that this will be a breaking change - the format of the props passed to ProgressIndicator has changed

Comment on lines +33 to +36
export class ProgressStep extends React.PureComponent {
constructor(props) {
super(props);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still trying to figure out what the status of this PR is, but we're actually working on making our components functional components for v11. Devs agreed that it makes more sense esp since most devs these days work with the latest React. We don't want this to be a class component.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ref: #9712

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, sorry, it looked like I needed to re-write some of the tests to get them to pass and unfortunately I haven't done it yet. I understand what you're saying about functional components, but I could not find a way to apply the animations without making it into a class component. Do you want to close this PR for the moment? I still plan to fix the failing tests, and I will review and seek advice on the feasibility of accomplishing the animation on a functional component.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious what issues you were running into with the functional component, and also if there are other ways we might be able to implement this without breaking changes. Referring to the stepData prop. Why is that needed instead of handling the props through ProgressStep? It's not our typical API pattern for data of parent/child components like Tabs, Accordion, ContentSwitcher. I think there's a bigger discussion to be had about the implementation.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please bear with my long explanation here 😅 I'll try to explain how/why I ended up doing it the way I did, and maybe we can come to a better solution - any thoughts or suggestions are greatly appreciated! I definitely agree it would be preferable to not introduce any breaking changes.

The issue I was having was how to prevent a re-render of all the ProgressStep components each time there was a change to the ProgressIndicator's props. Once I added in the CSS keyframes animations, the animations were re-triggered every time each ProgressStep was re-rendered, which caused a weird flashing effect (see below although please note that that is an earlier version that did not yet include the line animations, only the icon animations). The goal was for each ProgressStep & its icon to re-render only when there was a change to its status.

progress-tracker2.mp4

In the current implementation of ProgressIndicator.js, renderSteps() clones each child element each time there is a change to the ProgressIndicator's currentIndex, and so the cloneElement() is what was triggering the re-render. Instead of cloning the element, I wanted the element to persist but just change it's props if necessary. I first thought to use React.memo() but from my understanding, that is not something that can be used with React.Children. So that's how I ended up passing the StepData in to render the ProgressSteps with the newly added isCurrent and isComplete props, rather than rendering them as cloned React.Children. The solution I found was to use React.PureComponent to make use of its comparison of those props to only re-render a ProgressStep if it changes, hence the Class component.

As a next step, I addressed the lint and format errors, and I will take a look at the typical pattern for for handling parent/child components in the components you mentioned. (The PublicAPI-test is still failing but since we may eliminate the changes causing that fail, I will address it later if need be.) @matthewgallo will take a look at this as well and we will hopefully find a solution that will work as a functional component and also one without any breaking changes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @kristastarr sorry for the late reply. Thank you for that detailed explanation, it's very helpful. I'd really like to help get this into production since it's something our designers are interested in. I think going forward, we can do a few things:

  1. Make this an RFC or create a separate RFC to get more input from the rest of our dev team on the implementation.
  2. I am also planning on bringing this up in our next dev team meeting (this week), and hopefully get some thoughts on how we feel about the API changes. Maybe even think about alternate solutions.
  3. Based on feedback and input from the rest of the team, we can decide what to do, how to help, etc.

How does that sound?

@kristastarr kristastarr marked this pull request as draft October 19, 2021 17:51
@jnm2377
Copy link
Contributor

jnm2377 commented Dec 3, 2021

Hey @kristastarr After talking to our dev team, we would prefer for the component to keep the existing API, where the steps are rendered as children and not a prop data array. We've just found that our components that follow the data prop pattern can be a pain both for users and maintainers. It can just limit people sometimes. So our requests would be to keep the functional component and API as is.

It seems that this PR hasn't had some activity for quite some time, so I'm going to close this for now. Please feel free to open another PR with these changes once you're ready. 🙂

@kristastarr
Copy link
Author

I am still planning to work on implementing the animation with a functional component. If yes, I will check in with y’all to see if I should do a new PR to Carbon, and if not we will plan to incorporate it into the Carbon for IBM products.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Progress Indicator Animations
4 participants