-
Notifications
You must be signed in to change notification settings - Fork 7
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 greedy navigation #3265
base: main
Are you sure you want to change the base?
Conversation
b48faf2
to
3959295
Compare
99cc2a2
to
86e43ab
Compare
3959295
to
9178f8c
Compare
86e43ab
to
d23da8c
Compare
9178f8c
to
aebda2b
Compare
d23da8c
to
b0cd126
Compare
aebda2b
to
44bb450
Compare
a40f707
to
eec7980
Compare
0a7bd33
to
f8c88c8
Compare
label: 'Components/Header', | ||
label: 'Components/Header (search open)', |
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 previously had the same name as another scenario, surprised it didn't clash before!
.component-preview--navigation, | ||
.component-preview--header { |
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.
Updated these rules so the header component examples also have their margin removed. This is why the header visual regression snapshots have updated for those examples too.
|
||
/** @define navigation */ | ||
// ============================================================================ |
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've moved all the navigation styles including single-use mixins into this file as they were previously split across three.
I've also expanded all the selectors so there's minimal shorthand. I've got a strong preference against them and this refactoring reminded me why: it's much nicer if you can just search for the whole classname.
@@ -0,0 +1,81 @@ | |||
/** |
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've kept this around as a basic initialisation test but honestly given the cypress tests cover everything anyway and are much better suited I'm inclined to delete this completely? How do folks feel about that? It's a pretty fake test as it stands.
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 getting rid of it is fine
return containerEl.clientWidth - padding; | ||
} | ||
|
||
function computeChildrenOffsetWidth(containerEl: HTMLElement) { |
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 used to have a 10 pixel offset but the rationale in the comment wasn't clear what benefit it gave. We can add it back if others disagree.
3ff4a96
to
b9d8377
Compare
11cfee1
to
84ed690
Compare
6b9dc18
to
8ca2a23
Compare
84ed690
to
20eea4d
Compare
Currently we have a couple of papercuts with our packaged javascript modules 1. The method of importing and initialising them is inconsistent 2. The typescript configuration needed is relatively complex for a small number of modules This commit attempts to rationalise that so that we have a consistent pattern for importing and initialising all modules and as a side-benefit a simpler typescript configuration. - Defines a top-level tsconfig.json that works for all modules and removes any per-module configuration needed - Adds consistent index.ts files to every module with a flexible set of default and named exports - Adds a wrapper method to greedy nav to allow it to be initialised in the same way as all other modules The goal is to support the existing import paths whilst enabling a consistent preferred method using named exports: ``` import { initMyModule } from "@citizensadvice/design-system/lib/my-module" ``` I've also included a `lib/index.ts` file so you can import from a single entrypoint: ``` import { initModuleA, initModuleB } from "@citizensadvice/design-system/lib" ``` Ideally we'd support importing directly from `@citizensadvice/design-system` but that needs further restructuring to make this work so something for a future release.
Summary ======= Introduces a new version of the greedy navigation component with greatly simplified code and improved behaviour. Motivation for change ===================== The greedy navigation component is one of our oldest components and was adapted from an external component. It's long been a pain point of the application as it is hard for the team to modify leading to patch work amends and redundant behaviour being maintained. The main motivation for change is that the component uses the icon font for the toggle button and we'd like to get rid of this in favour of SVG icons for all components. This requires change. The component is extremely hard to change so we should make the change easy by restructuring the component to only contain the behaviour we need and to match the rest of our components. The old component also has a completely different API to the rest of our components so this is a good opportunity to make that consistent. Configuration free ================== The new component is configuration free. The old component provided a number of configuration options many of which were partially implemented or redundant. The exception being label text which is now translated as part of the Rails template. The new component is initialised like all our other components. ```js import { initNavigation } from '@citizensadvice/design-system/lib'; initNavigation(); ``` Improvements ============ Restructuring the component enables a number of improvements: 1. Switches the icon to an SVG version (the original motivation for change) 2. Improves keyboard and mouse support (tabbing and clicking in and out of the menu now behaves more consistently) 3. Minimises flash of unstyled content (fix ported from the public website) 3. Bundles welsh translations for UI text. Previously this had to be provided as part of the component initialisation (translations taken taken from the public website). 4. Fixes mistranslation of aria-labels (in production when translated they are part welsh part english) 5. Removed significant amounts of redundant behaviour that was brought over from the module we modified. Backwards compatibility ======================= To make it easier to migrate to the new component I've kept the old entrypoint around which wraps the new implementation. This allows us to ship the new version with everything need as part of the library and we can remove the old entrypoint in a subsequent version.
Causes a conflict with the sticky navigation styles
20eea4d
to
6c51428
Compare
🚀 Netlify deployed citizens-advice-design-system as draft https://661fa42e2b512217036c5028--citizens-advice-design-system.netlify.app |
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 looks good to me. Some minor comments, it would be good to document doesItFit()
a bit more (and maybe call it something more appropriate (it seems to hide / show elements too - but I might have misunderstood!).
// We use https://github.com/dmtrKovalenko/cypress-real-events | ||
// to approximate this but full keyboard testing should still be | ||
// done manually when changing this behaviour. | ||
context('when interacting with a keyboard', () => { |
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 also test tabbing into it? If it's too fraught at least some sort of note to test that behaviour manually too?
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'll need to double check again, I think the answer is still that cypress doesn't handle that well so yes maybe a document that is manual testing steps for greedy nav would be good.
@@ -7,17 +7,6 @@ body { | |||
height: 100%; | |||
} | |||
|
|||
// https://philipwalton.github.io/solved-by-flexbox/demos/sticky-footer/ |
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.
was this causing problems with the navigation?
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.
Yes as a side-effect of porting over the overflow fix from public-website rather than the refactor itself.
@@ -0,0 +1,81 @@ | |||
/** |
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 getting rid of it is fine
return sum; | ||
} | ||
|
||
function doesItFit(containerEl: HTMLElement, breaks: number[]) { |
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.
What is breaks here? I think it has something to do with the cumulative widths of each nav link but it would be good to make it explicit (in a comment would be fine I think).
In fact some documentation for this function would be good - it's hard to infer the behaviour from the code fully.
Also it seems to do more than answer the question 'does it fit' - should it be broken up or renamed?
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.
Good shout.
Short answer: Agreed, let's break this down more.
Longer answer: For context the the process I followed was basically to copy over the existing file and names and gradually refactor the implementation, rather than a ground-up rewrite. I'd bet on this being part that retains the most naming of the original.
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.
OK - I'm happy for it to stay like this then and maybe this can be a smaller refactor later down the line. It would be good to have another look at it at some point tho.
display: none; | ||
//// | ||
// Prevent overflowing navigation when loaded | ||
// or when javascript is disable |
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.
disabled
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.
Happy for doesItFit
to be sorted out in another refactor later 👍🏻
Summary
Introduces a new version of the greedy navigation component with greatly simplified code and improved behaviour.
Motivation for change
The greedy navigation component is one of our oldest components and was adapted from an external component. It's long been a pain point of the application as it is hard for the team to modify leading to patch work amends and redundant behaviour being maintained.
The main motivation for change is that the component uses the icon font for the toggle button and we'd like to get rid of this in favour of SVG icons for all components.
This requires change. The component is extremely hard to change so we should make the change easy by restructuring the component to only contain the behaviour we need and to match the rest of our components.
The old component also has a completely different API to the rest of our components so this is a good opportunity to make that consistent.
Improvements
Restructuring the component enables a number of improvements:
Keyboard support
The old component had partial keyboard support but it was patchy. You could trigger the menu via keyboard but in a non-default way by tabbing in (but only in one direction). The component used a mouse up event instead of a typical click so you couldn't control the button with the space bar like a regular button.
The new behaviour is:
Configuration free
The new component is configuration free. The old component provided a number of configuration options many of which were partially implemented or redundant.
The exception being label text which is now translated as part of the Rails template.
The new component is initialised like all our other components.
Testing strategy
Previously we had a mix of tests split across jest and cypress. The jest tests ran assertions against internal methods rather than using testing library helpers. Using jest for component tests is limited as they have to work against static fixtures and don't run in a real browser. Our cypress tests run in a real browser and against real examples but previously only covered some behaviour but not the actual greedy nav logic.
I've taken the approach of keeping a basic jest test around to make sure the component isn't completely broken and then pushed the majority of the test scenarios into the cypress tests. These now cover the logic around moving items into the greedy navigation, keyboard interaction (within the limit of cypress' abilities), and translation behaviour.
Backwards compatibility
To make it easier to migrate to the new component I've kept the old entrypoint around which wraps the new implementation. This allows us to ship the new version and then remove the old entrypoint in a subsequent version.
The exploratory work for this was done in #3264 in case you want to see the process. Depends on #3260