-
Notifications
You must be signed in to change notification settings - Fork 1
Core 750: proper custom controls #2433
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
base: main
Are you sure you want to change the base?
Conversation
…er-custom-controls
…/rex-web into CORE-750-proper-custom-controls
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 made some notes. It's looking good.
src/app/content/components/TableOfContents/keyboardSupport.hook.tsx
Outdated
Show resolved
Hide resolved
src/app/content/components/TableOfContents/keyboardSupport.hook.tsx
Outdated
Show resolved
Hide resolved
src/app/content/components/TableOfContents/keyboardSupport.hook.tsx
Outdated
Show resolved
Hide resolved
src/app/content/components/TableOfContents/keyboardSupport.hook.tsx
Outdated
Show resolved
Hide resolved
src/app/content/components/TableOfContents/keyboardSupport.hook.tsx
Outdated
Show resolved
Hide resolved
src/app/content/components/TableOfContents/keyboardSupport.hook.tsx
Outdated
Show resolved
Hide resolved
src/app/content/components/TableOfContents/keyboardSupport.hook.tsx
Outdated
Show resolved
Hide resolved
src/app/content/components/TableOfContents/keyboardSupport.hook.tsx
Outdated
Show resolved
Hide resolved
src/app/content/components/TableOfContents/keyboardSupport.hook.tsx
Outdated
Show resolved
Hide resolved
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.
Looks good to me.
@TomWoodward could you help me with a review here ? |
playwright/src/fixtures/toc.ts
Outdated
@@ -33,7 +33,7 @@ class TOC { | |||
|
|||
async unitIntroCount() { | |||
// Total number of unit introduction pages in the book | |||
const unitIntroPageLocator = this.page.locator('//li[@data-type="unit"]/details/ol[1]/li[1][@data-type="page"]') | |||
const unitIntroPageLocator = this.page.locator('//li[@data-type="unit"]/a/ol[1]/li[1][@data-type="page"]') |
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.
isn't this no longer true? if its true i would be worried about putting lists inside an anchor, but i'm pretty sure you updated that already
src/app/components/Details.tsx
Outdated
|
||
// Other components than ToC use Details, so we need to style them separately | ||
// tslint:disable-next-line:variable-name | ||
export const DetailsTree = styled.a` |
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've left these elements named the way they were before but they no longer really make sense with those names. this component no longer acts like a details
component because the tree that it expands is not inside of it, its now more of a CollapseToggle
or something like that.
onClick(); | ||
} | ||
|
||
navigate(navigationMatch, options); |
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.
onclick has the navigate inside of it, you don't have to call it again
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.
Removing navigate(navigationMatch, options)
produce that page doesn't update the content. It means maybe this navigation is important. The onClick() call doesn't bring an invoke of navigation.
*/ | ||
e.preventDefault(); | ||
|
||
if (hasUnsavedHighlight && !await showConfirmation(services)) { |
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 is duplicated from the onclick, i would extract a handler used in both callbacks
@@ -95,14 +96,30 @@ export const ContentLink = (props: React.PropsWithChildren<Props>) => { | |||
navigate(navigationMatch, options); | |||
} | |||
}} | |||
onKeyDown={(e) => onKeyDown?.(e, async() => { | |||
/* | |||
All this logic has to be inside onKeyDown === Enter || Space |
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 you be checking the key pressed here? i don't see that filtering happening anywhere
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 i'm like 90% sure you don't need to specially handle pressing a link with the enter key, pretty sure it triggers the onClick
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.
Yeah I was sure that will work but that was not the case. I have to preventDefault behavior of keys because Tree navigation is very special. Removing preventDefault and 'enter' as one of my cases of keyboardSupport just do nothing. I'll explore more about it
return { filteredTreeItems, currentItemIndex }; | ||
} | ||
|
||
export const onKeyDownNavGroupSupport = ({ |
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.
export const onKeyDownNavGroupSupport = ({ | |
export const treeNavSubtreeOnKeyDown = ({ |
might make it more clear what this function is for
} | ||
}; | ||
|
||
export const onKeyDownNavItemSupport = ({ |
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.
export const onKeyDownNavItemSupport = ({ | |
export const treeNavItemOnKeyDown = ({ |
); | ||
let index = pageElements.indexOf(document?.activeElement as HTMLElement); | ||
if (shiftKey) { | ||
focusFirstTreeItem(filteredTreeItems); |
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.
why are you changing the treeitem focus and then focusing something else right after?
document?.querySelector<HTMLElement>(`[id="${filteredTreeItems[filteredTreeItems.length - 1]?.id}"]`)?.focus(); | ||
}; | ||
|
||
const focusOnTab = (filteredTreeItems: Element[], shiftKey: boolean) => { |
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 comments on these functions might be necessary, what is this doing that the regular browser tab doesn't?
|
||
const focusOnTab = (filteredTreeItems: Element[], shiftKey: boolean) => { | ||
const pageElements = Array.from( | ||
document?.querySelectorAll('input, button, select, textarea, a[href]') as ArrayLike<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.
i think there is a bigger list of tabbable elements in the repo somewhere
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 went back and reviewed the w3c page on the tree pattern, and in particular the markup structure and event handlers don't seem to be lining up with what I see in the pr. Notably I didn't think our toggles are supposed to be links because they didn't go anywhere. It also seems like the JavaScript example they have there might solve some of the issues I've been noting in your event handlers.
We might consider using the react aria library that we use in other places, they have a tree view component and I think their library is generally pretty extensible in terms of display styling
Hmmm I see... it is weird because when I was reviewing w3c page, the structure of using anchors as toggles is right there and that is why I kept using it. Probably I'll start a new PR from zero then. |
@TomWoodward It is true that we are using links that don't go anywhere, but this was done this way following the W3C example, which clearly shows that role=treeitem elements should be links in this pattern. When you mention that "the markup structure and event handlers don't seem to be lining up with what I see in the PR," could you clarify what you mean by that? I'm asking because the context of TableOfContents differs from the example provided. We have a dynamic tree in a context that involves handling a specific structure for reading data, such as book, page, section, among others. Regarding your comment about using react-aria-components, I get the impression that you are suggesting I should remove my code entirely and use the library instead. Is that correct? Also, I understand that this change would come from ui-components, which implies a more general implementation. On another note, when using the Tree from react-aria-components, I’ve noticed that its keyboard interaction implementation is somewhat limited. Additionally, the way styles are managed is different from what we currently have, which could lead to a greater effort to avoid breaking any existing functionality. Given that there are many doubts and concerns, and since I don’t fully understand your vision on this, I would prefer if we could meet and review the code together. This way, we can clear up any misunderstandings. |
look again, those links go places, in the example they provide there are index pages for each subtree that we don't have. in the react-aria implementation it looks like they actually don't have role=treeitem on the folder nodes that can't be selected
they have example javascript for handling keyboard events which looks simpler than yours, handles fewer events, overrides less default functionality (the tab key for example)
my suggestion to use react-aria-components is because we seem to be struggling to get this right, and that library is designed to solve this problem for us. i'm not sure if the treeview component that i've been referencing is a perfect fit, maybe they have something else, but it seemed like it might be worth looking into. i like using react-aria-components because the whole point of it is to follow the w3c standards by default so we don't have to worry about it. not saying we have to go that route, but i think its worth considering. i'm not suggesting that you do it through the ui-components library though (unless that makes sense for some other reason), you could also just implement the react-aria dependency right in rex. |
Card: https://openstax.atlassian.net/browse/CORE-750