-
Notifications
You must be signed in to change notification settings - Fork 55
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
feat(listitembase): dynamic list support #600
base: master
Are you sure you want to change the base?
Conversation
@@ -271,6 +271,24 @@ const ListItemBase = (props: Props, providedRef: RefOrCallbackRef) => { | |||
}; | |||
}, []); | |||
|
|||
useEffect(() => { |
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.
issue: This breaks looping lists if one of the ends is considered empty - maybe not a huge issue, but it doesn't behave as expected.
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 now fixed
} | ||
} | ||
} | ||
}, [focus, lastCurrentFocus, listContext.listSize]); |
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.
suggestion: I think this should include indexItem
and probably listContext.setCurrentFocus
(the latter is admittedly the result of a useState
so not hugely important, but this module doesn't really know what it is based on the context).
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 added the full list of dependencies to the useEffect
if (lastCurrentFocus > itemIndex) { | ||
if (itemIndex <= 0) { | ||
listContext.setCurrentFocus(itemIndex + 1); | ||
} else { | ||
listContext.setCurrentFocus(itemIndex - 1); | ||
} | ||
} else { | ||
if (itemIndex >= listContext.listSize - 1) { | ||
listContext.setCurrentFocus(itemIndex - 1); | ||
} else { | ||
listContext.setCurrentFocus(itemIndex + 1); | ||
} |
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.
suggestion: Some comments to explain what is happening would be useful - with some analysis you can see that you are actively keeping items at the (direction dependent) previous item if this item is at one of the ends, and otherwise skipping it, but it's not necessarily simple at a glance (the comment would have also made it clear that looping wouldn't work any more).
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 now fixed
src/components/List/List.stories.tsx
Outdated
const ListWithNullElementsWrapper = () => { | ||
return ( | ||
<> | ||
<List noLoop listSize={7}> |
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.
issue: This is a list of length 9 (looping will happen to work going down because this number is wrong!).
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.
fixed
clip: rect(0 0 0 0); | ||
clip-path: inset(50%); | ||
height: 1px; | ||
overflow: hidden; | ||
position: absolute; | ||
width: 1px; | ||
white-space: nowrap; |
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.
nitpick: This is another instance of the "visually hidden" styling which is in various parts of the library, would be nice to mixin / include this in scss terms.
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.
as far as I know, we don't currently have shared scss between the new components?
… into allow_empty_list_items
… into allow_empty_list_items
/** | ||
* event fired when any of the children or the element itself are focused | ||
*/ | ||
onFocusWithin?: (e: React.FocusEvent<Element>) => void; | ||
|
||
/** | ||
* event fired when any of the children or the element itself lose focus | ||
*/ | ||
onBlurWithin?: (e: React.FocusEvent<Element>) => void; | ||
/** | ||
* event fired when any of the children or the element itself are focused | ||
*/ | ||
onFocus?: (e: React.FocusEvent<Element>) => void; | ||
|
||
/** | ||
* event fired when any of the children or the element itself lose focus | ||
*/ | ||
onBlur?: (e: React.FocusEvent<Element>) => void; |
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.
Props
should extends FocusProps
and FocusWithinProps
instead of manually adding the props. JSDocs should be moved to the original definition.
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'm now extending this definition using the props from react-aria. Note that it isn't as simple as extending directly, because I haven't added support for all of FocusProps or all of FocusWithinProps
src/components/List/List.stories.tsx
Outdated
return ( | ||
<> | ||
<List shouldFocusOnPress listSize={2}> | ||
<ListItemBase data-exclude-focus-children size="auto" itemIndex={0} key={0}> |
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 the expected behaviour for data-exclude-focus
and data-exclude-focus-children
? I can see they might be excluded from intractable element selection, but it is not prevent the browser focus the element with Tab.
I check this story, and I can focus on button 1 with Tab.
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 removed the exclude-focus-children as this was covered by your recent changes. data-exclude-focus is used by the Aria-Toolbar. The toolbar only wants to expose one of its tabable buttons to preserve focus order when you tab forward/backward from within a ListItemBase. It sets data-exclude-focus on all but the first one so the first element is the only one to ever be in the tab order.
src/hooks/useFocusState.ts
Outdated
if (props.onFocusWithin) { | ||
props.onFocusWithin.apply(this, args); | ||
} |
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.
nitpicking: this can be simplified to:
if (props.onFocusWithin) { | |
props.onFocusWithin.apply(this, args); | |
} | |
props.onFocusWithin?.(...args); |
because the arrow functions this
is undefined
anyway
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 changed this
…omentum-react-v2 into allow_empty_list_items
… into allow_empty_list_items
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.
Tested locally and changes look good to me. A few small comments
const ListWithNonFocusableChildrenWrapper = () => { | ||
return ( | ||
<> | ||
<List shouldFocusOnPress listSize={2}> | ||
<ListItemBase data-preserve-tabindex size="auto" itemIndex={0} key={0}> | ||
<ButtonPill>1</ButtonPill> | ||
</ListItemBase> | ||
<ListItemBase itemIndex={1} key={1}> | ||
<ButtonPill>2</ButtonPill> | ||
</ListItemBase> | ||
</List> | ||
</> | ||
); | ||
}; | ||
const ListWithNonFocusableChildren = Template<unknown>(ListWithNonFocusableChildrenWrapper).bind( | ||
{} | ||
); |
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 story doesn't seem to be working as expected
} | ||
}; | ||
|
||
useEffect(() => { | ||
// When the toolbar is rendered inside a list, only item in the toolbar |
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.
"only one item" or "only the first item"
getContext: () => { | ||
listSize: number; | ||
currentFocus: number; | ||
setCurrentFocus: Dispatch<SetStateAction<number>>; | ||
shouldFocusOnPress?: boolean; | ||
shouldItemFocusBeInset?: boolean; | ||
noLoop?: boolean; | ||
updateFocusBlocked?: boolean; | ||
supressFocus?: 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.
supressFocus is never used so can be removed
Description
This PR contains a number of improvements to List/ListItemBase:
Links
Links to relevent resources.