react-spectrum icon indicating copy to clipboard operation
react-spectrum copied to clipboard

Improve extensibility

Open IIIristraM opened this issue 1 year ago β€’ 7 comments

πŸ™‹ Feature Request

At this moment react-aria has no exports of implemented collections and delegate behaviours (like TableCollection, TableKeyboardDelegate), also state hooks based on collections (like useTableState) have no options to pass your own collection that implements same interface

πŸ€” Expected Behavior

  • collections and delegate behaviours are listed in library exports
  • state hooks have options to pass a custom class / factory to use custom collections

😯 Current Behavior

At this moment you can ether copy the entire files with collections / delegate behaviours to be able to inherit own class from them, or import them from source files (src dir), which leads to problems with project build as far as you need to process TypeScript files placed in node_modules.

πŸ’ Possible Solution

  • add exports of collection / delegate classes in index files
  • add option to state hooks to pass your own collection that implements an appropriate interface

πŸ”¦ Context

I need to add sections for tables (like a panel that aggregates some rows and can be toggled), sections can be nested.

I split this problem into following steps

  • write my custom TableBody component that can iterate through Section components
  • write my custom TableWithSectionsCollection that extends TableCollection and process sections into rows that can be parsed by TableCollection
  • write my custom TableWithSectionsDelegate that extends TableKeyboardDelegate in order to avoid keyboard navigation on rows that are hidden by closed section
  • write useTableWithSectionState hook that 99% copy of useTableState but uses TableWithSectionsCollection

so I faced problems described above that TableCollection and TableKeyboardDelegate are not exported and useTableState has no option to pass my own collection, and it seems like same problems exists for other react-aria packages

IIIristraM avatar Aug 15 '22 09:08 IIIristraM

You actually can implement the Collection Interface yourself. It’s exported under @react-types/shared. The useTableState hook expects props that conform to the CollectionBase<T> interface, which is exported from @react-types/shared. It’s just a typescript interface, so you could write anything to conform to it.

https://react-spectrum.adobe.com/react-stately/Collection.html#building-a-collection

I agree that some of these types should be exported from the packages themselves, but I believe that is something the team is aware of, and working on.

tanishqkancharla avatar Aug 18 '22 02:08 tanishqkancharla

@tanishqkancharla, I'm talking about implementations in first place, not about types. TableCollection has a lot of logic under the hood, and it extends GridCollection that also contains a lot of code, and all this code is useful for me, I don't want to duplicate same logic in my custom collection, I want to inherit this logic and overwrite or extend some methods. Same about TableKeyboardDelegate. It seems like a couple of extra exports in index files with this classes cost nothing, and could be released as patch for any version, and bring a lot of help.

IIIristraM avatar Aug 18 '22 12:08 IIIristraM

I see, I thought you were talking about the abstract CollectionBase<T>, not the concrete TableCollection

tanishqkancharla avatar Aug 18 '22 14:08 tanishqkancharla

I think what you're trying to do will require more than just changing the collection/keyboard delegate. You are describing an ARIA treegrid. This has a different role and behaviors than currently used by useTable, so you'd need to override all that as well. A keyboard delegate would not be sufficient to implement the keyboard control for expanding/collapsing rows for example. We will eventually support the treegrid pattern in React Aria itself.

That said, a keyboardDelegate can already be passed in, and I would like to support passing in a pre-built collection as well. I just don't think it would be sufficient to build what you're describing.

devongovett avatar Aug 19 '22 18:08 devongovett

@devongovett Well, actualy I'm not trying, I've made such component. It supports correct keybord navigation for sections, avoiding closed ones, closing/opening of sections by space/enter, selecting all rows in sections when selection is enabled, marking selection as indeterminate when some rows in section not selected including subsections etc. And yep it required not only custom collection and delegate logic but also custom Section snd TableBody components, custom hooks for section checkboxes and extending GridNode with additional links that help in section navigation. But still, most of the code is in collection an delegate classes, which inherit from TableCollection and TableKeyboardDelegate, tightly depending on their implementation.

It would be great if at some point such component would be presented in react-aria out of the box, but I need it now, and I just hope it would be possible to import required classes, instead of dirty ways like copy-pasting these files or including source code from node_modules in webpack build.

Also there're could be less complex cases when these exports could be handy, for example useTable support disabledKeys only to avoid selection but you still able to navigate over disabled rows, that could be unexpected, and logic like skipping disabled rows on navigation can be achived by quite simple extention of TableKeyboardDelegate, if it would be exported

IIIristraM avatar Aug 19 '22 20:08 IIIristraM

The team discussed this today, we'd be ok with exporting TableCollection and TableKeyboardDelegate as well as expanding the stately hooks so that they accept a pre-built collection. We don't have a good estimate for when we'd pick up this work due to other priorities so we'd welcome any contributions!

LFDanLu avatar Aug 25 '22 00:08 LFDanLu

@LFDanLu, I've made PR

IIIristraM avatar Aug 25 '22 14:08 IIIristraM