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
Issue19 a11y #21
Issue19 a11y #21
Conversation
-makes it tabbable -providing it shortcut keys to enter and exit the wrapped child component.
…sing a screenreader.
@philpl @kentcdodds here's that PR |
I played with the demo and the interaction is great! One thing is it's unclear when I'm focused on the tabgate, so it's hard to know where the keyboard focus is. Normally the browser will give an outline to the focused element. Could we make sure there's some styling for |
Huh. Thought I saw the outline in mine. I'll explicitly add that style so there's zero question. |
@kentcdodds The code is now adding a more explicitly styled outline |
Cool. Here's what it looks like for me: So by adding the margin and padding on focus it's making things kinda jump around a little bit. I'd also rather this be done with regular CSS rather than inline styles and JavaScript events. In addition, the blue outline is sub-optimal IMO. I wonder if there's another way we could highlight that it's focused... Ok, I did a little bit of digging and just realized two things:
From here, I can copy the |
Awwww yaaa! I'm a huge fan of not doing the javascript-y css-y outline I added. Happy to see it cleared up. Deleting code is always more satisfying than adding it in my book. I didn't look too much at the styled components, great find. It is satisfying to see in action, the gifs are such a nice way to show off page interaction. |
We could just include the TabGate in the editor but I was thinking (see my comments in the original issue) why can't we implement this just using I mean we could include the TabGate code in the editor and call it a day, but why do we need this: @alexlande has made a modification a while ago where the editor's tab-capturing behaviour can be disabled: react-live/src/components/Editor/index.js Line 105 in 5677482
We can just add an enter handler there in an I think that's a much more elegant solution and we're really close to it already :) Thanks for your effort already :) Looking great! |
Yup, I'm definitely more interested/excited about |
@philpl A lot of the design decisions were made with desire of avoiding touching existing code and behaviors. For this reason, code like the One thing to watch for Keyboard: tab to Editor -> hit 'Enter' -> trigger whatever happens on activating the editor for change Both would reset whatever flag Also because the editor is the active element we need to address what happens when the user types keys after focus. I assume this flag we'd store in state seems like it would drive two different branches of interactions when keys are pressed. One for the 'focused and waiting to enter' state and the other for the 'focused and editing' state. Instead of introducing a flag would it make sense to use the Edge cases are the trouble makers in these kind of scenarios. |
Cheers! 🎉 😄
So we'd have to make sure that
It should probably skip the enter guard as well. I'd assume that if the user starts typing, that he's intentionally typing to edit the code.
Well, then the behaviour before is tricky. If we manage to reproduce all of this with just the |
@philpl moved the logic over to where you directed, does this look more like what you were looking for? For styling of the outline I introduced some css and added the following logic:
For navigation:
All in all there is now an |
Could you provide a gif? I use LICECap 😄 |
react-live.css
Outdated
@@ -92,3 +92,9 @@ | |||
.token.deleted { | |||
color: red; | |||
} | |||
|
|||
.tabGuarded{ |
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 don't think that this CSS is needed. The user agent styles should be good enough right? If it's not showing up, perhaps it's that overflow: hidden
issue I mentioned earlier...
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.
The problem is that now we are directly focusing the editor so it will have an outline the entire duration of the editing.... or that's what I was seeing. I'll mess with the overflow you mentioned.
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.
https://github.com/burge-is/react-live/blob/24be04a17906ff8641d1df29cc0f4c00dce24717/react-live.css#L13
There is an outline: hidden
being applied to the .prism-code
that wasn't in play with the old TabGate
code. The TabGate
had a wrapper and that is where we were outlining before, now it's directly on the Editor
with it's existing css. I say this having spent more time typing then messing with the CSS.
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.
Looked into it further and deleting the overflow: hidden
didn't work for me. It's the change in implementation of previously having a wrapper but now dealing directly with the Editor
. Could be wrong though, but it's what I am seeing.
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.
Interesting. Thanks for digging. Let's see what @philpl has to say 😄
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.
The outline code is fine. The user should be able to deal with the details of how it should look :)
But can we put it at the top of the file, rename it to .tab-guarded
, and make the rule more specific please (i.e. .prism-code.tab-guarded
)? Cheers :)
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.
Btw it'll also need to be added here: https://raw.githubusercontent.com/FormidableLabs/react-live/master/src/constants/css.js
Sorry for that not being in one file right now :(
src/constants/css.js
Outdated
@@ -93,4 +93,10 @@ export default ` | |||
.token.deleted { | |||
color: red; | |||
} | |||
|
|||
.tabGuarded{ |
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.
Some comment here
Nice! Thanks for sharing that! Yeah, I think that there's the |
I kind of like the addition of the class for the purposes of styling or possible adding in the ARIA tips that were talked about in the issue thread. Provides some context by way of class. But if removing that fixes it all again, it's another one of those win wins you mentioned and I can delete some lines of code. Checking now. Also, thanks for the software tip. I really like this. Now to find what I see some streamers using to display the keys they are pressing on screen. |
You might be interested in this 😄 |
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.
just some minor code comments that we need to fix but it's overall looking good
react-live.css
Outdated
@@ -92,3 +92,9 @@ | |||
.token.deleted { | |||
color: red; | |||
} | |||
|
|||
.tabGuarded{ | |||
outline: 1px dotted #212121; |
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 instead make this solid? I don't think dotted
looks rather native.
src/components/Editor/index.js
Outdated
document.execCommand('insertHTML', false, '	') | ||
evt.preventDefault() | ||
} else if (evt.keyCode === 13) { // Enter Key | ||
if(!this.tabGuarded){ |
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.
You can just wrap this into the above if
statement.
Also we can remove the ignoreTabKey
prop now, as the new behaviour is supposed to replace it.
src/components/Editor/index.js
Outdated
} | ||
}else if (evt.keyCode && evt.keyCode === 27) {//Esc Key | ||
this.tabGuarded=true | ||
this.ref.classList.add("tabGuarded") |
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 just replace the ref
usage and the tabGuarded
flag with a flag inside the component state? In this case we don't need to be clever about how to handle the element, and can just use the lifecycle instead :)
src/components/Editor/index.js
Outdated
evt.preventDefault() | ||
} | ||
}else if (evt.keyCode && evt.keyCode === 27) {//Esc Key | ||
this.tabGuarded=true |
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.
There's some stylistic divergence here (=
instead of =
). Can you fix this please? I promise I'll add prettier to this project soon ;)
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.
Also when you move the flag over to the state you might want to add a check for !tabGuarded
here
src/components/Editor/index.js
Outdated
onBlur = evt => { | ||
this.tabGuarded =true | ||
this.ref.classList.remove("tabGuarded") | ||
return evt |
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 and the above doesn't need to return anything ;)
But we need to proxy both callbacks to potential props like the existing ones do:
if (this.props.onKeyDown) {
this.props.onKeyDown(evt)
}
@philpl here's most of the suggested changes. When I originally added the flag I put it in the state. However, this got tricky during I considered adding code for when should the state actually render / managing focus upon render but it felt more mentally taxing to consume than the idea of dealing with classList / a boolean flag on the object. Toying with it again this A.M. a bit to see what it would look like if I can get it to behave within the lifecycle. |
Moved |
@burge-is amazing! I'll review it again once I'm at my desk and merge it. Don't worry about the difference in coding style. I'll just add prettier later 👍 thanks again! |
Thanks so much for working on this @burge-is! This is going to be great for keyboard-only users. a11y FTW! |
Thanks for tweeting this issue out @kentcdodds , my first go at contributing to open source and I learned a lot from you and @philpl during the process. Keep up the good work on y'alls end. |
src/components/Editor/index.js
Outdated
}else if (evt.keyCode === 27) {// Esc Key | ||
this.setState({tabGuarded:true}) | ||
}else if(!(evt.shiftKey || evt.ctrlKey || evt.altKey)){ | ||
this.setState({tabGuarded:false}) |
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.
Hm, okay. I see what prompted you to use the flag before. This state change triggers early so that the selection save (this.selection = ...
) in the keyup handler isn't respected on enter.
So now when the enter key is pressed the state changes, the component updates, and the selection is harmed.
We can try an easy fix. First of all we can add the flags to the if statement && this.state.tabGuarded) {
etc
Then we can maybe move this logic into the keyup handler. It has to be after the rest of the logic there. ^^
Makes sense?
Almost there now! Sorry, I found a bug with the enter key not respecting the saved selection 😢 |
…ot interfere with all preceding key handling
Pesky render. The logic for changing state is now at the end of |
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.
Found another small bug
src/components/Editor/index.js
Outdated
|
||
if (evt.keyCode === 27 && !this.state.tabGuarded) {// Esc Key | ||
this.setState({tabGuarded:true}) | ||
}else if(!(evt.shiftKey || evt.keyCode === 27 || evt.keyCode === 9) && this.state.tabGuarded){ |
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.
In keyup
the shift
key (19) triggers separately when released. So here you'll need to add evt.keyCode === 16
as well. Just discovered that :/
Also, can we do this.state.tabGuarded && !evt.shiftKey && evt.keyCode !== 27 /* ... */
instead? i.e. negate the group there to remove it, and put the tabGuarded
first? Should help readability a little.
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.
Definitely, I'll be a little more thorough with the key clicking this go round after the change 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.
✨ Accessibility ✨ — it's tough
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.
Is the behavior your'e seeing a shift press is being treated as hitting any old key (the assume desire to edit on any key press logic)? That would be expected based on how I was thinking of it, the evt.shiftKey was originally put in to handle shift tabbing not necessarily an independent shift press.
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.
Which I'm thinking shift+tab may be broken in the newest implementation not gonna lie I expect this out of event handlers. They have that wonderful ability to get tangled up like earbuds in a pocket if you aren't careful with your approach. Kind of why I originally wrapped the whole thing in a blocking div. The past trauma of dealing with edge cases was giving me flashbacks. I'll dig a little bit further later this evening.
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.
@burge-is Yep, exactly, shift+tab is broken
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 just realised that we're being a bit silly here haha 😆 We can actually just set tabGuarded
to false inside an onChange
handler. So we create a new callback method, proxy it up and:
onChange = evt => {
if (this.props.onChange) {
this.props.onChange(evt)
}
if (this.state.tabGuarded) {
this.setState({ tabGuarded:false })
}
}
That should work, right?
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.
Sooooo much prettier. That's a much better way to conceptualize it. I couldn't see the forest for the trees. It reads more like English and that always feels nice. Gets us out of that keycode "magic number" hell 🔥👿🔥
Abstractions are a developer's best friend.
… attempts to change the contents of Editor
Not quite there, I wrote it inline and tested with good results and was hasty with commiting after placing the function on the component up with the other |
@burge-is I think I'm not seeing any bugs anymore so it should be good to go? The only thing is, that I'm not seeing the highlighting / outline in the demo. I thought this must've worked sometime before, given that Kent posted a gif with it above? |
… a focus causing a temporary outline that is immediately removed. tabGuarded is now reset onBlur instead of having any handlers in onFocus onClick logic moved to bottom of the handelr as to not interfere with seleciton logic
Hmmm... my As far as the outline you need to make sure wherever you are testing is getting the latest css, when checking in demo I had to go manually replace that minified css file. I just switched over to trying it out on the storybook code so that I could more rapidly check my changes and I am seeing the outline on focus. I corrected the margin hoppy-ness while looking it over. As well as shifted logic away from But the |
…b or escape you are editing.
I made the last check in So, funny to see my original over-engineered wrapper next to these small changes. Coding is growing .... or in this case shrinking. |
@burge-is I'll review it this evening 😄 looking really solid now! Yea, oftentimes the optimal solution ends up being simpler than any initial approach.... If one's lucky |
In the future, you shouldn't need to worry about it, maintainers can just choose the "Squash and Merge" feature which will squash all changes into a single commit. It's pretty rad. Alternatively, you can cleanup a PR yourself using an interactive rebase 😄 |
Yea, don't worry about it 😄 But it's not an issue, let's continue with the new PR |
@kentcdodds very good to know, thank you. |
Issue #19
Adds a component to the demo code to handle keyboard accessibility.
The component:
role='alert'
tooltip when focused to announce new keyboard nav shortcuts (enter/esc)