Comments (9)
My first thought here would be it would be a breaking change if we changed how things like empty state was provided to a collection component (or at least we'd have to deprecate renderEmptyState
and support both ways of providing it). As for allowing the render function of the ListBox to have renderProps, is there a particular use case you are trying to achieve with it? The contents of the ListBox itself are pretty specific and rigid (aka it expects only sections and items) so it feels like it would mainly be used for styling based on the state of the listbox but the ListBoxItem's themselves have access to renderProps in their own render functions for this.
from react-spectrum.
Yup, this would absolutely be a breaking change, but in the name of consistency, flexibility and extensibility.
And just to reiterate, this is not exclusive to the ListBox. It is applicable to all RAC that implement the Collection API.
The use case is being able to access the entire collection state at the top level. Which would allow for the creation of custom components that can maintain the flexibility of static and dynamic collection items without needing to reimplement and control state.
This would enable the custom component to establish functionality based on this collection state such as filtering, searching, custom layout, etc. Alternatively, the custom component could establish context slots for composition of this functionality.
MyCustomComponent (receives all props of below RAC plus any custom, passes them through)
AnyRACCollectionComponent
MyCustomComponentInner (receives render props from above RAC plus any custom from parent)
Here the Inner component now has full access to the RAC internal state and nothing had to be reimplemented. It can now choose to establish slots with a Provider or custom layout and functionality, etc. And MyCustomComponent retained all of the flexibility of the underlying RAC
from react-spectrum.
A more concrete example would be to implement a De/Select All button. This would contextually need to know the state of the whole collection, what is currently selected, and access to the selection manager to be able to call methods.
As things currently stand the only way to do this is to drop support for statically defined items, implement useControlledState and useListState, and control the RAC completely from the parent thereby also allowing for the state and selection manager to be exposed as described above
With the proposed changes, the entire complexity of reimplementing state and selection would be negated
from react-spectrum.
I see, we've have historically suggested that users drop down to the hooks levels at this point but I see your point about wanting more flexibility here by making the Collection RAC components support more of a wrapper like api. I remember there were issues in the past (infinite rerenders/etc) when trying to provide the internal state object via render props for some of the collection components like ComboBox and Select, but those are a bit of a different case so I'm not sure if the same issues would arise. I'll bring this up with the team and see what opinions they have.
from react-spectrum.
Talked with the team and maybe the work in #6608 can help enable this for you. The exported Collection stuff from that PR will allow you to follow the same pattern that ComboBox and Select have aka the ListBox creates the collection of items that Combobox/Select can then use in their own hooks. That sounds like the structure you want here where you are sharing the state between a parent component and the actual collection component that is generating the collection of items.
We are a bit wary of performing the original proposed changes since it is such a big breaking change and since we weren't sure it would actually work in the dynamic case due to the parent state needing the collection to be passed in which would be problematic if ListBoxItems was now responsible for setting up the collection via CollectionBuilder (aka it is now at a lower level than were the top level state is setup)
from react-spectrum.
I'll check out the PR you linked in detail tomorrow. In the meantime, my gut reaction to how to make the original proposal work would be to have <ListBoxItems>
be required to implement a slot prop, such that <ListBox>
would pass down a ref and be able to access state / children. Technically unnecessary if the <ListBoxItems>
's context is just implemented on the DEFAULT_SLOT
. Just an untested idea:
<ListBox
aria-label="Pick a Pokemon"
items={list.items}
selectionMode="single"
>
<ListBoxItems slot="items">{(item) => <ListBoxItem id={item.name}>{item.name}</ListBoxItem>}</ListBoxItems>
<EmptyState slot="empty">No items</EmptyState>
</ListBox>
<ListBox
aria-label="Pick a Pokemon"
selectionMode="single"
>
<ListBoxItems slot="items">
<ListBoxItem>Foo</ListBoxItem>
<ListBoxItem>Bar</ListBoxItem>
</ListBoxItems>
<EmptyState slot="empty">No items</EmptyState>
</ListBox>
So, <ListBox
, implements <Provider values={[[ListboxItemsContext, { ref: itemsRef }]]}>
. And potentially instead of the ref attaching to the DOM node, it connects to an imperative handle that exposes access to it's collection, maybe?
from react-spectrum.
The problem is that there's a circular dependency. In order to construct the state, you first need the collection. So we can't pass the state as a render prop because it depends on the children which would be returned by the render prop function rendering first.
from react-spectrum.
True, the initial render would be guaranteed to have an empty collection in the case of static jsx options (items prop would fulfill per usual, immediate if static, on second render if asynchronous/dynamic) until it was able to retrieve that state. Maybe not perfect, but not unworkable, and actually consistent with the asynchronous dynamic items
from react-spectrum.
Alternative approach: Support a third type of rendering combination
- Approach 1: items is undefined, children are static jsx collection items
- Approach 2: items is an array, children is an iterator function
- Approach 3: items is an array, children is a new component
<CollectionRenderProps>{(renderProps) => {...}}</CollectionRenderProps>
; where renderProps represents the full render props state of the parent RAC, which would include the collection, selectionManager, and any other applicable state (already outlined in the RAC's style renderProps)
No breaking change, no circular dependency, full access to internal state. Win, win, win?
And it should be relatively easy to determine which approach is being utilized to change how the collection is initialized
The only downside is the lack of support for static jsx items combined with being able to access render props children
from react-spectrum.
Related Issues (20)
- usePress wrapper on a text input swallows space key presses HOT 3
- SelectItem missing ref prop while ListboxItem implements/exposes it. HOT 6
- [RAC] Add autoscroll config to AriaLink HOT 1
- [RAC] Breaking change to `children` type in `BreadcrumbProps` in v1.3.2 HOT 1
- Date and time not updating with shouldCloseOnSelect equals false in DateRangePicker from react-aria-components HOT 1
- Type param in SelectProps<T> is not used HOT 5
- SelectValue shows placeholder when the selected value label is 0 HOT 9
- Long tag names are not truncated to fit in parent container HOT 1
- Update state when visibleRange changes in <RangeCalendar> HOT 5
- [react-aria] FocusScope with contain prevents programmatic scrolling when `prefers-reduced-motion: reduced` and `scroll-behaviour: auto` is given HOT 5
- Use `null` instead of `Number.NaN` in NumberField component HOT 1
- Button inside label triggers dropdown to open HOT 1
- Add `isToday` to `CalendarCellRenderProps` HOT 2
- Re-rendering the entire list of elements (ComboBox list) HOT 5
- Remix Link with useLink causes FocusRing to appear when clicked HOT 5
- Native validation doesn't dismiss errors as the user corrects them HOT 11
- Expose `isRTL` utility function
- useDateSegment crashes on null reference during unmount HOT 1
- Adjusting screen reader (VoiceOver MacOS) reading order for a react-aria-components HOT 1
- Context Slots are not Extensible HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from react-spectrum.