-
Notifications
You must be signed in to change notification settings - Fork 13
feat: active/passive focus styling #511
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
Conversation
@BenHenning to take a look at the rest of "other outstanding issues with no obvious plugin-only fix" to make sure there are no required breaking changes. |
@@ -35,6 +40,25 @@ export class KeyboardNavigation { | |||
*/ | |||
private originalTheme: Blockly.Theme; | |||
|
|||
/** |
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.
@BenHenning also to check whether this needs to happen in core.
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.
@microbit-matt-hillsdon a few questions:
- Does the ring div have to be a child of the injection div or can it be a child of workspace?
- If the latter, is it possible to use styling to enable/disable the ring focus if the parent (i.e. workspace) has active focus? That would eliminate the need for the additional focus listeners (which would be preferred since we're trying to route all focus management through
FocusManager
).
If the above can be done, this won't require an API breaking change in Core.
If this style cannot be achieved without overlaying a div on top of the workspace g
element, then this does get more complicated. Perhaps we can use a group element inside workspace with customized dimensions that subtract the toolbox + flyout so that it's just the main work area that's highlighted, and add that to the bottom of the workspace so that it always renders above everything? Still not a breaking change, I think, but perhaps a bit complicated.
If it truly needs to be a div then we can still tweak it's on/off behavior in WorkspaceSvg
's own onFocusNode
/onBlurNode
callbacks. In fact, a quick proof-of-concept would be to swap those methods out here in place of custom focusin
/focusout
listeners. If that works, the change in Core for a managed div is pretty straightforward.
So long as we don't need to figure out a way to hook in this new sibling to workspace into focus, I don't expect any breaking API changes to be needed.
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.
Thanks, makes sense to try other options. Ran out of time today but will pick this up tomorrow.
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.
It cannot be achieved within the SVG, which cannot draw over the toolbox. However, recent discussions around global navigation led me to rethink whether this was desirable vs outlining the same area the workspace scrollbars are drawn in (i.e. workspace minus toolbox area). I've updated the PR to do that with a rect in the workspace SVG. That corresponds better to the global nav areas in MakeCode. Also removed the focus listeners.
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 really like this latest solution. It's pretty much exactly what I was envisioning, and should be really straightforward to move into core when we get to that point.
There's a bit of a bigger open question around InputModeTracker
as part of solving google/blockly#8852 but that can be worked on after this PR is merged. InputModeTracker
seems quite sensible at this point and for the needs of this PR.
I also asked @maribethb to take a quick pass on the new tracker and her thoughts were:
I think the approach is fine enough but has problems, because one of the things with tracking is that doing something like copying with ctrl+c doesn't mean that a user is using keyboard navigation, so doing this with global event listeners is not going to be the right approach in the long term. but if we use the same class name, this is easy enough to update because we wouldn't have to update any styles, and then we can just use a more sophisticated way to track the mode, and delete the global event listeners
I think if these edge cases around copying and pasting (as specific examples) are fine with you @microbit-matt-hillsdon then it seems completely reasonable to merge this as-is and we can later, as Maribeth mentioned, figure out a better tracking system that interoperates with the new CSS classes (or some variation on them).
stroke: #ffa200; | ||
stroke-width: 5; | ||
.blocklyPassiveFocus.blocklyHighlightedConnectionPath { | ||
/* The connection path is being unexpectedly hidden in core */ |
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.
@microbit-matt-hillsdon could you provide a bit more context on the breakage you found here? Connections are hidden until they're selected. Is it the case that they're highlighting but then moving them to passive focus causes them to disappear again?
That would be a miss on my part, if so, and would make complete sense since some of the selection bits have changed yet again in google/blockly#9004.
This would need a fix in Core but I wouldn't expect it to be an API breakage. We need to maybe use something other than display to enable/disable the connection highlighting, instead. This might actually be best fixed as part of google/blockly#8942 since CSS should make this a lot easier.
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.
Prior to this change we found there was no passive focus connection path at all as it had display: none
set by core. I suppose this might be about to go away due to other work but I wanted to see it and check it worked as expected if styled.
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.
Got it. I'm not opposed to the !important
bit, but we'll of course need to fix this properly when it comes time to move this all over to core. This discussion thread will probably be helpful as part of that work.
Thanks @microbit-matt-hillsdon! This is a very nice set of fixes over the rough current state of passive/active focus. I've left a few thoughts on code directly, otherwise I have in-line replies to various concerns in your PR description below:
This is probably a remnant of test changes that I had around selection that I unintentionally included in the Core plugin (but I'd have to do some code archaeology to confirm). I think removing it seems completely reasonable as we haven't yet fully moved selection over to CSS.
The specific behavior with selection disappearing is a regression and has been filed in google/blockly#9027. There's a separate question about passive focus here. I think we can probably disable passive focus for blocks if they are selected, but that's supposed to be impossible. If we find a clean way to fix the selection issue while dragging then the passive focus problem should go away, too.
Just to check, this is only for shift tabbing once in the workspace, correct? If so, this will require more discussion as there may be an explicit need to be able to tab to the workspace (to open the workspace context menu with redundancy/consistency with regular keyboard navigation). There's a small chance a proper long-term fix here would require breaking API changes. The unknown is how to let
So from local testing it seems removing Edit: This isn't a perfect fix as it will break the insertion flow (i.e. there's no indicator where a block will be added during insertion). I suspect this could be fixed more specifically by checking if the editor is open, but that could become rather field-specific. I think this depends a lot on what the desired behavior is. Once insertion starts, selection takes over and you properly see where the block will be added. It's only an issue for losing context while the toolbox is open (which perhaps is something we don't actually care about, anyway).
These seem like the same problems (mostly), and I see three different pathways here:
I suspect that the compatibility question is that |
Also for bookkeeping, as far as I can tell this PR could fix all of the following:
Plus perhaps several other issues mentioned in the findings document that haven't had corresponding issues filed. |
NB: The gist also fixes google/blockly#8969. |
0636668
to
cbd4b3b
Compare
Yes, let's move discussion to google/blockly#8965
I think it's useful context for the insertion flow. Made a suggestion on #508 and won't apply your change here for now (I confirmed it works except for this though). I'll get other input on the value of the context though and follow up separately.
Do nothing might be OK in the short term where MakeCode plan to ship keyboard nav as a setting, but not sure it's a good plan for an on-by-default future. Other clients may have different plans, would be good to get more input. Leaning towards your second option but I think it's one of those things you have to try to decide whether it's too weird.
I think we might need a fix for this but can split it out. |
Per your last point @microbit-matt-hillsdon I will send out a PR today that adds a bunch of new classes for trees. I'm specifically thinking:
I think this gives maximum flexibility to solve some of the more complex styling edge cases. |
## The basics - [x] I [validated my changes](https://developers.google.com/blockly/guides/contribute/core#making_and_verifying_a_change) ## The details ### Resolves Fixes #9027 ### Proposed Changes Ensure that a block being dragged is properly focused mid-drag. ### Reason for Changes Focus seems to be lost due to the block being moved to the drag layer, so re-focusing the block ensures that it remains both actively focused and selected while dragging. The regression was likely caused when block selection was moved to be fully synced based on active focus. ### Test Coverage This has been manually verified in Core's simple playground. At the time of the PR being opened, this couldn't be tested in the test environment for the experimental keyboard navigation plugin since there's a navigation connection issue there that needs to be resolved to test movement. It would be helpful to add a new test case for the underlying problem (i.e. ensuring that the block holds focus mid-drag) as part of resolving #8915. ### Documentation No new documentation should need to be added. ### Additional Information This was found during the development of google/blockly-keyboard-experimentation#511.
Both of these should now be fixed in the latest v12 per #521 (comment). |
Following up to this: I created google/blockly#9046. It doesn't cover subtree focus, and I thought of a different approach for field editing (by latching onto ephemeral focus). The ephemeral focus bit especially needs to be tested in this plugin since I'm not sure if it'll work. Separately, this PR has a low chance of making it into v12 tomorrow since I'm not going to be comfortable merging it without thorough focus manager tests. I'll try to get it done, but it's my lowest priority PR to try and get in before the release. |
cbd4b3b
to
d8f004e
Compare
Rebased and updated the PR comment. A key change to highlight is I've added tracking of the most recent input method and used it to hide keyboard-oriented styles. I think I'd call this ready for review if it wasn't for the dependency on #520. Not the last word in styling for sure but a good step forward. |
#520 now merged! |
- Fix connection passive focus (unexpectedly display: none) - Limit passive focus to the workspace - Add active tree focus outlines - Limit focus styling to when keyboard nav is enabled (based on last input event)
d8f004e
to
6e78753
Compare
This affects MakeCode during initialization.
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.
Thanks @microbit-matt-hillsdon! I think the solutions here are really solid, and they feel quite a bit better than current main
tip-of-tree when I played around with it locally.
I left some follow-up comments, but I largely think this can be merged as-is. As noted there's still some follow-up work needed (and some design questions for when we eventually move these changes into core).
FYI that the failing tests are probably due to #525 which I'll be looking into (though note I didn't actually look at the failures on this branch closely, I'm just assuming that it's due to this).
stroke: #ffa200; | ||
stroke-dasharray: 5px 3px; | ||
stroke-width: 3px; | ||
* { |
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.
Do we really always want to do this for everything, or should this be done specifically to toolbox and other related cases?
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 it's the right thing for the demo page, but a more nuanced discussion when moving into core or even CSS applied automatically by plugin. Something like this is in every modern CSS reset going, so it's likely to be present in many environments Blockly operates in.
.blocklyKeyboardNavigation | ||
.blocklyActiveFocus:is(.blocklyPath, .blocklyHighlightedConnectionPath), | ||
.blocklyKeyboardNavigation | ||
.blocklyActiveFocus.blocklyField | ||
> .blocklyFieldRect { |
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.
.blocklyKeyboardNavigation | |
.blocklyActiveFocus:is(.blocklyPath, .blocklyHighlightedConnectionPath), | |
.blocklyKeyboardNavigation | |
.blocklyActiveFocus.blocklyField | |
> .blocklyFieldRect { | |
.blocklyKeyboardNavigation | |
.blocklyActiveFocus:is(.blocklyPath, .blocklyHighlightedConnectionPath, .blocklyField > .blocklyFieldRect) { |
(Wrapping needed)
Does this work, by any chance? Maybe a small simplification.
Ditto for passive focus, as well.
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 this works because the second selector in the original needs to select the .blocklyFieldRect
which unlike the others, isn't the element with .blocklyActiveFocus
but a child. Tested locally.
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.
Ah I was hoping nesting the child selector in the is()
would work, but it looks like it doesn't then. I appreciate you double checking.
stroke: #ffa200; | ||
stroke-width: 5; | ||
.blocklyPassiveFocus.blocklyHighlightedConnectionPath { | ||
/* The connection path is being unexpectedly hidden in core */ |
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.
Got it. I'm not opposed to the !important
bit, but we'll of course need to fix this properly when it comes time to move this all over to core. This discussion thread will probably be helpful as part of that work.
@@ -35,6 +40,25 @@ export class KeyboardNavigation { | |||
*/ | |||
private originalTheme: Blockly.Theme; | |||
|
|||
/** |
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 really like this latest solution. It's pretty much exactly what I was envisioning, and should be really straightforward to move into core when we get to that point.
There's a bit of a bigger open question around InputModeTracker
as part of solving google/blockly#8852 but that can be worked on after this PR is merged. InputModeTracker
seems quite sensible at this point and for the needs of this PR.
I also asked @maribethb to take a quick pass on the new tracker and her thoughts were:
I think the approach is fine enough but has problems, because one of the things with tracking is that doing something like copying with ctrl+c doesn't mean that a user is using keyboard navigation, so doing this with global event listeners is not going to be the right approach in the long term. but if we use the same class name, this is easy enough to update because we wouldn't have to update any styles, and then we can just use a more sophisticated way to track the mode, and delete the global event listeners
I think if these edge cases around copying and pasting (as specific examples) are fine with you @microbit-matt-hillsdon then it seems completely reasonable to merge this as-is and we can later, as Maribeth mentioned, figure out a better tracking system that interoperates with the new CSS classes (or some variation on them).
Re input mode tracking, I think copy itself behaves well. It's paste and similar cases (if any?) where we programatically move focus in response to a keypress that wasn't a traditional focus move key press or an action we added that is keyboard oriented (like 't' for toolbox) rather than mixed-mode like paste. Perhaps just filtering keydown events to those that have the right intent (tab/shift-tab/t/w?) would be enough to address these cases. This likely needs action integration for the latter two. But I think this is a step forward at least and will help us enumerate the awkward cases. |
Co-authored-by: Ben Henning <[email protected]>
Thanks for the review @BenHenning. From my point of view it would be good to merge now and then tweak as needed with smaller changes. |
Sounds good @microbit-matt-hillsdon. Will take care of merging this soon. Just working on fixing #525 so that I can ensure that these tests will pass once that's addressed (at which point I'm happy to merge this even with broken CI). |
When merging in #527 and linking against google/blockly#9063 all tests seem to pass (there was a slight scare where I thought one was failing but I think this was just a caching fluke when changing branches & re-linking since everything passed in subsequent attempts). Going ahead and merging this while we sort out the CI failures in #527. |
Depends on #520 so it can build against latest v12. Clean diff vs that branch.
Demo: https://passive-focus.blockly-keyboard-experimentation.pages.dev/ (built against latest v12)
Closes #507
Closes google/blockly#8966
Closes google/blockly#8964
Obviously all the CSS is still in the index.html so we should consider whether it should move for a plugin release or whether each integrator needs to copy/paste/tweak.
Key changes:
box-sizing: border-box
. We think most apps will do this and it avoids the toolbox's default padding moving it slightly off the bottom of the screen (noticeable when adding an outline).Serious outstanding issues that can feel broken or confusing:
Move mode is quite broken with a passive and active selection showing at onceMouse drags show passive focus but that feels wrong when you're interacting with the passive thing. We think this behaviour should not change from current Blockly.Other outstanding issues