-
Notifications
You must be signed in to change notification settings - Fork 86
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(step-flow): add new component #6481
Conversation
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. Latest deployment of this branch, based on commit 810ecb2:
|
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.
Great effort @tomdavies73, especially on the considerations you've given to accessibility. I've left some comments but they're fairly straightforward to address, on the whole really good work 👏
flex-direction: column; | ||
`; | ||
|
||
const StyledCategoryText = styled(Typography)` |
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.
Comment: we can probably just use Typography
here directly as it already supports the interface for all this styling
|
||
const StyledTitleTextContainer = styled.span``; | ||
|
||
const StyledVisibleTitleText = styled.span` |
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.
Comment: if you simplify the HTML like Ive suggested above you can probably just pass these to Typography
directly
|
||
const StyledProgressIndicator = styled.span<StyledProgressIndicatorProps>` | ||
background-color: ${({ isCompleted, isInProgress }) => | ||
calculateProgressIndicatorColor({ isCompleted, isInProgress })}; |
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.
suggestion (non-blocking): you don't need to destructure here props
are passed implicitly so you could just do:
background-color: ${calculateProgressIndicatorColor};
background-color: ${({ isCompleted, isInProgress }) => | ||
calculateProgressIndicatorColor({ isCompleted, isInProgress })}; | ||
width: 100%; | ||
height: 8px; |
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.
comment: wherever possible we should use tokens such as --spacing150
, --borderRadius100
etc.
Comment relates to whole file (font sizes etc)
/** Set the variant of the internal 'Typography' component which contains the category. | ||
* However, despite the chosen variant the styling will always be overridden. | ||
*/ | ||
categoryTypographyVariant?: VariantTypes; |
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.
categoryTypographyVariant?: VariantTypes; | |
categoryVariant? :Extract<VariantTypes, "h1" | "h2" | "h3" | "h4" | "h5" | "p">; |
Naming is non-blocking for me but I think we should limit the elements here as some don't seem viable for this use case
return ( | ||
<StyledStepFlow {...rest} {...tagComponent("step-flow", rest)}> | ||
<StyledStepContent> | ||
<StyledStepContentText> |
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.
Comment: this would render an empty container if no category
is set. We could probably get away with using Typography
directly here is we add support for aria-hidden
etc
); | ||
}); | ||
|
||
const closeIcon = ( |
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.
comment: lets add an aria-label here and support translations on it etc
await checkAccessibility(page); | ||
}); | ||
|
||
test("should pass accessibility checks when 'showCloseIcon' is true", async ({ |
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.
suggestion: maybe worth focusing the close icon and then checking against axe here
); | ||
|
||
expect( | ||
container.querySelector('[data-element="close"]') |
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.
comment: if we set and aria-label (see above) we can get by label here instead of using a container to query.
|
||
<StyledSystemProps of={StepFlow} margin noHeader /> | ||
|
||
<TranslationKeysTable |
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.
comment: don't forget to update this with the close aria label
c896c6d
to
dfa7725
Compare
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.
Excellent work on this, @tomdavies73. Just a few comments from me, nothing serious though 😄👍🏻
|
||
const testData = [CHARACTERS.DIACRITICS, CHARACTERS.SPECIALCHARACTERS]; | ||
|
||
test.describe("Prop checks for Portrait component", () => { |
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.
typo:
test.describe("Prop checks for Portrait component", () => { | |
test.describe("Prop checks for Step Flow component", () => { |
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.
Genuinely do not know how i missed this
<StepFlowComponent currentStep={1} totalSteps={1} showProgressIndicator /> | ||
); | ||
|
||
const backgroundColorToken = await getDesignTokensByCssProperty( |
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.
suggestion(non-blocking): You may not need this await here.
const backgroundColorToken = await getDesignTokensByCssProperty( | |
const backgroundColorToken = getDesignTokensByCssProperty( |
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.
I think we do need an await here as its a promise, without it backgroundColorToken
returns undefined
<StepFlowComponent currentStep={2} totalSteps={3} showProgressIndicator /> | ||
); | ||
|
||
const backgroundColorToken = await getDesignTokensByCssProperty( |
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.
suggestion(non-blocking): Same again. You may not need this await here.
const backgroundColorToken = await getDesignTokensByCssProperty( | |
const backgroundColorToken = getDesignTokensByCssProperty( |
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.
I think we do need an await here as its a promise, without it backgroundColorToken
returns undefined
<StepFlowComponent currentStep={2} totalSteps={3} showProgressIndicator /> | ||
); | ||
|
||
const backgroundColorToken = await getDesignTokensByCssProperty( |
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.
suggestion(non-blocking): Same again. You may not need this await here.
const backgroundColorToken = await getDesignTokensByCssProperty( | |
const backgroundColorToken = getDesignTokensByCssProperty( |
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.
I think we do need an await here as its a promise, without it backgroundColorToken
returns undefined
await stepFlowDismissIcon(page).click(); | ||
expect(callbackCount).toBe(1); |
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.
nitpick(non-blocking): space here otherwise the QA's will break your legs.
await stepFlowDismissIcon(page).click(); | |
expect(callbackCount).toBe(1); | |
await stepFlowDismissIcon(page).click(); | |
expect(callbackCount).toBe(1); |
await button(page).nth(1).click(); | ||
await expect(stepFlowTitleTextWrapper(page)).toBeFocused(); |
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.
nitpick(non-blocking): Same again with the broken legs.
await button(page).nth(1).click(); | |
await expect(stepFlowTitleTextWrapper(page)).toBeFocused(); | |
await button(page).nth(1).click(); | |
await expect(stepFlowTitleTextWrapper(page)).toBeFocused(); |
await checkAccessibility(page); | ||
}); | ||
|
||
test("should pass accessibility checks when component is rendered with a ref", async ({ |
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.
suggestion(non-blocking): Just because the example is called StepFlowComponentWithRefAndButtons
test("should pass accessibility checks when component is rendered with a ref", async ({ | |
test("should pass accessibility checks when component is rendered with a ref and buttons", async ({ |
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.
Real good updates @tomdavies73, especially how thorough you've been in adding additional testing 👍
|
||
it("when the 'titleVariant' prop is not passed, the variant is h1 by default", () => { | ||
const { container } = render( | ||
<StepFlow title="this title is a h1" currentStep={5} totalSteps={6} /> |
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.
comment (non-blocking, don't actually change anything): I suppose depending if you say aitch or haitch could affect whether it's a h1
or an h1
here 😆
const user = userEvent.setup(); | ||
const { container } = render(<MockComponent />); | ||
const button = screen.getByRole("button"); | ||
button.focus(); |
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.
comment: I don't think you need to focus the button here (just click) and given the what this is testing it may be a little confusing
@@ -39,9 +40,9 @@ import StepFlow from "carbon-react/lib/components/step-flow"; | |||
|
|||
## Examples | |||
|
|||
The `titleRef` prop is mandatory, and must be passed when the component is used to ensure focus is pulled to the components title whenever | |||
A `ref` is **strongly** recommended to be used, to ensure focus is programmatically moved to a a title div when |
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.
Suggestion (non-blocking):
To ensure focus is programmatically moved to the `title` of a given `StepFlow` when a user advances through each step, pass a `ref` is **strongly** recommended. This ensures screen reader users are made aware of all information throughout the user journey
We (myself and @tempertemper )are happy with the suggested accessibility solution, however request from a semantic pov that the current h1/h2/h3 spec is changed to span/h1/span, and the ability to change the h1 semantically to h2 if required. Visually nothing will change from the design. |
57e4c8d
0ac1747
to
810ecb2
Compare
As discussed with @tempertemper changes made so only the title is h1 by default but can be changed to a h2 and the Category and steps are now just spans. |
creates a new carbon component to aid consumers in creating and offering means for end users to advance through a user journey. The component also has built-in accessibility considerations with a custom ref handle being provided which provides consumers with the ability to programmatically move focus to a visually hidden DOM element which consists of a formatted string with the relevant title, category, and step progress
🎉 This PR is included in version 125.11.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
Proposed behaviour
This PR will add the
StepFlow
component which aims to help users advance through a user journey, and keep track of their progress. This is done initially with a very simple default configuration, with just the current title, current step and the total steps in the journey. This can also be contextualised further with an optionalcategory
prop.However, a progress indicator can also be rendered via the
showProgressIndicator
prop, providing an added decorative indicator of progress, with indicators holding three individual states: completed, in progress, not completed ; each with their own background colours.A close icon can also be rendered, with its own
onDismiss
prop, allowing consumers to pass functions to be called onClick such as closing a modal.The component is also flexible, allowing for multiple steps to be set with the
currentStep
andtotalSteps
props, both can be between 1-8. AlsocurrentStep
can never exceed the value oftotalSteps
. When these are changed, the label underneath the title will change, as well as the indicator bar (if rendered).The component also has built-in accessibility considerations with a focus ref being provided which provides consumers with the ability to pull focus to a visually hidden DOM element containing a formatted string with all of the relevant titles, category, step progress contained within.
This ensures screen reader users are given all the relevant information through semantic HTML on first navigation, and then when they progress through the journey, using buttons, for example focus is then pulled to the DOM element shown above. This will announce all of the relevant text content and then allow them to navigate down the page through all the relevant content below.
Current behaviour
Currently there is no accessible component which provides means to track and display a step journey or sequence.
Checklist
d.ts
file added or updated if requiredQA
Additional context
Testing instructions
The following CodeSandbox is an example of the broken behaviour.
You can see the new behaviour by looking at the version in the comment by
codesandbox[bot]
.