Skip to content

Conversation

@devongovett
Copy link
Member

This removes Spectrum-specific logic from the layouts in @react-stately/layout, and moves that into subclasses within each Spectrum component. These include:

  • Loading and empty states
  • Overflow overrides
  • Height adjustments
  • Section header collection differences

It also adds backward compatibility for the layout prop of useTable which I previously removed. This is done by shimming the LayoutDelegate interface using a copied interface that matches the old Virtualizer Layout class so we don't need a dependency on it.

I also reverted the change to use overflow: clip because it resulted in incorrect height measurements (caught by Chromatic). This was originally because I thought it introduced additional generic containers in Firefox accessibility tree. I later realized that these only seem to affect VoiceOver which is not a supported combination. Firefox NVDA seems fine.

Finally I removed the workaround added 2 years ago for sticky positioning crashing in Chrome 105 (#3504). I think it's been fixed for long enough that we don't need this anymore.

rows = getAllByRole('row');
expect(rows).toHaveLength(8);
expect(rows.map(r => r.textContent)).toEqual(['FooBar', 'Foo 7Bar 7', 'Foo 8Bar 8', 'Foo 9Bar 9', 'Foo 10Bar 10', 'Foo 11Bar 11', 'Foo 12Bar 12', 'Foo 13Bar 13']);
expect(rows.map(r => r.textContent)).toEqual(['FooBar', 'Foo 8Bar 8', 'Foo 9Bar 9', 'Foo 10Bar 10', 'Foo 11Bar 11', 'Foo 12Bar 12', 'Foo 13Bar 13', 'Foo 14Bar 14']);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RAC table doesn't add + 1 for bottom row borders anymore as Spectrum does.

@rspbot
Copy link

rspbot commented Jun 25, 2024

@snowystinger
Copy link
Member

Based on your description, i guess #6611 (comment) is unneeded?

Copy link
Member

@snowystinger snowystinger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did a quick sweep of ListView and TableView as well as RAC virtualized Table and List, looks good, no crashes or anything dire

Copy link
Member

@LFDanLu LFDanLu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, chromatic ran clean and the virtualized stories for RAC/RSP seem to work as expected. Didn't find any other Spectrum specific logic other than maybe the +/- 10 thresholds for DnD in getDropTargetFromPoint that a user might want to be able to customize/specify but that one doesn't seem like a huge deal unless a user has much larger or smaller rows than our own I guess.

If a non-RSP user was previously relying on the Spectrum specific calculations in the layouts before, would the recommendation be that they essentially copy TableViewLayout/ListBoxLayout/etc aka extend from Table/ListLayout and add the same logic? I don't know if anyone was relying on those tbh so maybe it is fine

@devongovett
Copy link
Member Author

Yeah looks like the nubbin isn't clipped anymore on this PR.

@rspbot
Copy link

rspbot commented Jun 26, 2024

@rspbot
Copy link

rspbot commented Jun 26, 2024

## API Changes

unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any', access: 'private' }
unknown top level export { type: 'any', access: 'private' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'identifier', name: 'Column' }
unknown top level export { type: 'identifier', name: 'Column' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown type { type: 'link' }
unknown type { type: 'link' }
unknown type { type: 'link' }
unknown type { type: 'link' }
unknown type { type: 'link' }
unknown type { type: 'link' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
unknown top level export { type: 'any' }
undefined already in set

@react-spectrum/listbox

useListBoxLayout

 ListBoxBase<T> {
   autoFocus?: boolean | FocusStrategy
   disallowEmptySelection?: boolean
   domProps?: HTMLAttributes<HTMLElement>
   focusOnPointerEnter?: boolean
   isLoading?: boolean
-  layout: ListLayout<T>
+  layout: ListBoxLayout<T>
   onLoadMore?: () => void
   onScroll?: () => void
   renderEmptyState?: () => ReactNode
   shouldFocusWrap?: boolean
   shouldUseVirtualFocus?: boolean
   showLoadingSpinner?: boolean
   state: ListState<T>
 }
 

@react-stately/layout

ListLayoutOptions

 ListLayoutOptions {
-  L: undefined
+  estimatedHeadingHeight?: number
+  estimatedRowHeight?: number
+  headingHeight?: number
+  rowHeight?: number
 }

it changed:

  • ListLayout

ListLayoutProps

-ListLayoutProps {
-  isLoading?: boolean
-}
+

it changed:

  • ListLayout

LayoutNode

changed by:

  • LayoutNode
 LayoutNode {
   children?: Array<LayoutNode>
-  header?: LayoutInfo
   index?: number
   layoutInfo: LayoutInfo
   node?: Node<unknown>
   validRect: Rect
 

it changed:

  • LayoutNode

TableLayoutOptions

-TableLayoutOptions<T> {
-  scrollContainer?: 'table' | 'body'
-}
+

it changed:

  • TableLayout

ListLayout

changed by:

  • ListLayoutOptions
  • ListLayoutProps
-ListLayout<T> {
-  constructor: (ListLayoutOptions<T>) => void
-  getContentSize: () => void
-  getDropTargetFromPoint: (number, number, (DropTarget) => boolean) => DropTarget
-  getLayoutInfo: (Key) => void
-  getVisibleLayoutInfos: (Rect) => void
-  updateItemSize: (Key, Size) => void
-  validate: (InvalidationContext<ListLayoutProps>) => void
-}
+

TableLayout

changed by:

  • TableLayoutOptions
-TableLayout<T> {
-  collection: TableCollection<T>
-  columnWidths: Map<Key, number>
-  constructor: (TableLayoutOptions<T>) => void
-  getDropTargetFromPoint: (number, number, (DropTarget) => boolean) => DropTarget
-  getVisibleLayoutInfos: (Rect) => void
-  isLoading: any
-  lastCollection: TableCollection<T>
-  lastPersistedKeys: Set<Key>
-  persistedIndices: Map<Key, Array<number>>
-  scrollContainer: 'table' | 'body'
-  stickyColumnIndices: Array<number>
-  validate: (InvalidationContext<TableLayoutProps>) => void
-}
+

undefined

-
+ListLayout<O = any, T> {
+  constructor: (ListLayoutOptions) => void
+  getContentSize: () => void
+  getDropTargetFromPoint: (number, number, (DropTarget) => boolean) => DropTarget
+  getLayoutInfo: (Key) => void
+  getVisibleLayoutInfos: (Rect) => void
+  updateItemSize: (Key, Size) => void
+  validate: (InvalidationContext<O>) => void
+}

undefined

-
+TableLayout<O extends TableLayoutProps = TableLayoutProps, T> {
+  constructor: (ListLayoutOptions) => void
+  getDropTargetFromPoint: (number, number, (DropTarget) => boolean) => DropTarget
+  getVisibleLayoutInfos: (Rect) => void
+  validate: (InvalidationContext<TableLayoutProps>) => void
+}

@react-stately/virtualizer

Layout

 Layout<O = any, T extends {}> {
   getContentSize: () => Size
   getItemRect: (Key) => Rect
-  getLayoutInfo: (Key) => LayoutInfo
+  getLayoutInfo: (Key) => LayoutInfo | null
   getVisibleLayoutInfos: (Rect) => Array<LayoutInfo>
   getVisibleRect: () => Rect
   shouldInvalidate: (Rect, Rect) => boolean
   updateItemSize: (Key, Size) => boolean
   virtualizer: Virtualizer<{}, any, any>
 }
 

@devongovett devongovett merged commit 6288d4a into main Jun 26, 2024
@devongovett devongovett deleted the layout-refactor branch June 26, 2024 19:59
@devongovett devongovett mentioned this pull request Sep 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants