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

Screen reader notifications #355

Closed
wants to merge 8 commits into from
Closed

Screen reader notifications #355

wants to merge 8 commits into from

Conversation

cee-chen
Copy link
Member

Description

#320 redux - moving things out of views to SearchDriver 🚂

TODO - I'm opening this now to get some sanity checks/discussion points before moving further in my assumptions.

List of changes

TODO

Associated Github Issues

#325

- a11yNotifications flag/bool
- a11yNotificationMessages obj of functions (this feels like it has to be a state to be passed to the withSearch HOC, correct me if I'm wrong)
- a11yNotify action
@cee-chen cee-chen added the WIP label Jul 17, 2019
@cee-chen cee-chen changed the title A11y notifications Screen reader notifications Jul 17, 2019
@cee-chen
Copy link
Member Author

cee-chen commented Jul 17, 2019

@JasonStoltz and @yakhinvadim - I'd super appreciate your sanity checks on what direction to go with announcing search results.

  1. 487e24d - Use PagingInfoContainer from react-search-ui - this is pretty straightforward but it does mean that non-React users no longer gain screen reader accessibility.

  2. 4e87abf - Use SearchDriver from search-ui itself - this guarantees that all users will get this screen reader messaging. I think this is preferable, however, as you can see I now have to repeat the start/end calculation logic from PagingInfoContainer.

I'm pretty sure 2. is the way to go - if so, would you all be OK with moving the start/end logic to SearchDriver.js and passing it down from there for DRYness instead?

@@ -151,7 +165,8 @@ export default class SearchDriver {
// to the correct default values for the initial UI render
this.state = {
...this.state,
...searchParameters
...searchParameters,
...{ a11yNotificationMessages }
Copy link
Member Author

@cee-chen cee-chen Jul 17, 2019

Choose a reason for hiding this comment

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

actually - I'm not 100% sure, but should this really be in state? Or does it feel more like an action?

In theory you are calling functions, e.g. a11yNotificationMessages.searchResults({ ... }) to produce strings (e.g. Showing X out of Y ...), which makes me think this belongs more in actions than in state.

Copy link
Contributor

Choose a reason for hiding this comment

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

Please, take the following with a grain of salt, I'm not sure if I'm right or not.

They don't look like state - they don't change after initialization.
They also don't look like actions - you don't call them directly to change state.
Aren't they more like a part of a config?

Copy link
Member Author

@cee-chen cee-chen Jul 18, 2019

Choose a reason for hiding this comment

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

Yeah, I think I tend to agree with you. The thing is, I don't know how else to pass it down to the withSearch HOC though - since state and action are what get passed down, and we need views/users to be able to access the message functions somehow.

Should we maybe pass down a whole new key like getMessages or driver.messages?... 😬

Copy link
Contributor

@yakhinvadim yakhinvadim Jul 18, 2019

Choose a reason for hiding this comment

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

we need views/users to be able to access the message functions somehow

Why? I thought users would add these functions to config once and then not touch it anywhere in the components (in most cases). If (in rare cases) users need to change the a11y message for some reason manually, they would call one universal action a11yNotify.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, that was my impression too. I thought the only thing we were going to do with them is have the SearchDriver write them out to a DOM element.

Copy link
Member Author

@cee-chen cee-chen Jul 18, 2019

Choose a reason for hiding this comment

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

This makes the a11yNotify action feel much more legit now too. Thanks a billion! ✨

Copy link
Member Author

@cee-chen cee-chen Jul 18, 2019

Choose a reason for hiding this comment

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

Also, just one more follow-up to this refactor that I only just considered - if users want to roll their own completely custom a11y notification for, e.g. their completely custom component - they should accomplish this by extending the a11yNotificationMessages obj, correct? So, for example:

SearchDriver({
  a11yNotificationMessages: {
    customMessage: () => 'Hello world',
  },
});

This means that:

  1. We're now limiting the a11yNotify action to not simply allow strings - originally I was thinking users could do something like a11yNotify('Whatever I want!'), but that will no longer be the case with this architecture. Are we good with that? (I'm good with it personally, just checking that we're all on the same page.)

  2. Per 78ffd85, we're now limiting a11yNotificationMessages to only contain functions. For example, if someone tried to pass customMessage: 'Hello world', a type error would get thrown. Are we okay with this restriction? Or do we want to add a typeof function check to allow both primitive strings and functions? 🤔 (Feels a bit overkill to me and I'm fine with the limitation, but also wanted to check that we all agree.)

@JasonStoltz @yakhinvadim - would love your thoughts! 😀

Copy link
Member

Choose a reason for hiding this comment

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

@constancecchen Probably clearer for users to just always use functions. Easier to document, less code, smaller API surface.

Copy link
Contributor

Choose a reason for hiding this comment

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

(2) I agree with Jason

Copy link
Contributor

Choose a reason for hiding this comment

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

(1) I'm not 100% sure about this, more like 70%, but if you both think that that's ok, I'm in.

@yakhinvadim
Copy link
Contributor

I agree that 2 is the way to go. I'm also for storing the start/end logic in SearchDriver, I can't think of a case where a user would want to calculate it another way. This would also be very convenient for non-React users.

@JasonStoltz
Copy link
Member

@constancecchen I think you are spot on with option 2. That would be great.

const end =
totalResults <= start + resultsPerPage
? totalResults
: start + resultsPerPage - 1;
Copy link
Member Author

Choose a reason for hiding this comment

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

Following up here on our decision to move start/end logic out of PagingInfoContainer and into SearchDriver - are you guys good with this? Or is there a more elegant way/place to put this that I'm missing? 🤔

Here's the full commit for context: 4c58a73

Copy link
Member

Choose a reason for hiding this comment

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

@constancecchen This looks correct to me. Since these have moved to the global state, I think these should be renamed to give some more context. Maybe pagingStart and pagingEnd?

@cee-chen
Copy link
Member Author

Thanks so much for all the comments and help everyone! Sounds like we're good to go with this direction. I'm going to close this draft PR and open a new one that's been cleaned up and rebased (so we can keep this architecture discussion for reference but have a fresh start for code review). 🙏

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

Successfully merging this pull request may close these issues.

3 participants