@react-aria/virtualizer 4.0.4 → 4.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -44,7 +44,7 @@ function ScrollView(props: ScrollViewProps, ref: ForwardedRef<HTMLDivElement | n
44
44
 
45
45
  return (
46
46
  <div role="presentation" {...scrollViewProps} ref={ref}>
47
- <div role="presentation" {...contentProps}>
47
+ <div {...contentProps}>
48
48
  {props.children}
49
49
  </div>
50
50
  </div>
@@ -69,7 +69,7 @@ export function useScrollView(props: ScrollViewProps, ref: RefObject<HTMLElement
69
69
  scrollTop: 0,
70
70
  scrollLeft: 0,
71
71
  scrollEndTime: 0,
72
- scrollTimeout: null,
72
+ scrollTimeout: null as ReturnType<typeof setTimeout> | null,
73
73
  width: 0,
74
74
  height: 0,
75
75
  isScrolling: false
@@ -114,7 +114,10 @@ export function useScrollView(props: ScrollViewProps, ref: RefObject<HTMLElement
114
114
  if (state.scrollEndTime <= now + 50) {
115
115
  state.scrollEndTime = now + 300;
116
116
 
117
- clearTimeout(state.scrollTimeout);
117
+ if (state.scrollTimeout != null) {
118
+ clearTimeout(state.scrollTimeout);
119
+ }
120
+
118
121
  state.scrollTimeout = setTimeout(() => {
119
122
  state.isScrolling = false;
120
123
  setScrolling(false);
@@ -132,10 +135,13 @@ export function useScrollView(props: ScrollViewProps, ref: RefObject<HTMLElement
132
135
  // Attach event directly to ref so RAC Virtualizer doesn't need to send props upward.
133
136
  useEvent(ref, 'scroll', onScroll);
134
137
 
135
- // eslint-disable-next-line arrow-body-style
138
+
136
139
  useEffect(() => {
137
140
  return () => {
138
- clearTimeout(state.scrollTimeout);
141
+ if (state.scrollTimeout != null) {
142
+ clearTimeout(state.scrollTimeout);
143
+ }
144
+
139
145
  if (state.isScrolling) {
140
146
  window.dispatchEvent(new Event('tk.connect-observer'));
141
147
  }
@@ -146,7 +152,7 @@ export function useScrollView(props: ScrollViewProps, ref: RefObject<HTMLElement
146
152
  let isUpdatingSize = useRef(false);
147
153
  let updateSize = useEffectEvent((flush: typeof flushSync) => {
148
154
  let dom = ref.current;
149
- if (!dom && !isUpdatingSize.current) {
155
+ if (!dom || isUpdatingSize.current) {
150
156
  return;
151
157
  }
152
158
 
@@ -12,8 +12,8 @@
12
12
 
13
13
  import {Collection, Key, RefObject} from '@react-types/shared';
14
14
  import {Layout, Rect, ReusableView, useVirtualizerState} from '@react-stately/virtualizer';
15
- import {mergeProps, useLoadMore} from '@react-aria/utils';
16
- import React, {HTMLAttributes, ReactElement, ReactNode, useCallback, useRef} from 'react';
15
+ import {mergeProps, useLoadMore, useObjectRef} from '@react-aria/utils';
16
+ import React, {ForwardedRef, HTMLAttributes, ReactElement, ReactNode, useCallback} from 'react';
17
17
  import {ScrollView} from './ScrollView';
18
18
  import {VirtualizerItem} from './VirtualizerItem';
19
19
 
@@ -22,7 +22,7 @@ type RenderWrapper<T extends object, V> = (
22
22
  reusableView: ReusableView<T, V>,
23
23
  children: ReusableView<T, V>[],
24
24
  renderChildren: (views: ReusableView<T, V>[]) => ReactElement[]
25
- ) => ReactElement;
25
+ ) => ReactElement | null;
26
26
 
27
27
  interface VirtualizerProps<T extends object, V, O> extends Omit<HTMLAttributes<HTMLElement>, 'children'> {
28
28
  children: (type: string, content: T) => V,
@@ -36,32 +36,33 @@ interface VirtualizerProps<T extends object, V, O> extends Omit<HTMLAttributes<H
36
36
  layoutOptions?: O
37
37
  }
38
38
 
39
- function Virtualizer<T extends object, V extends ReactNode, O>(props: VirtualizerProps<T, V, O>, ref: RefObject<HTMLDivElement | null>) {
39
+ // forwardRef doesn't support generic parameters, so cast the result to the correct type
40
+ // https://stackoverflow.com/questions/58469229/react-with-typescript-generics-while-using-react-forwardref
41
+ export const Virtualizer = React.forwardRef(function Virtualizer<T extends object, V extends ReactNode, O>(props: VirtualizerProps<T, V, O>, forwardedRef: ForwardedRef<HTMLDivElement | null>) {
40
42
  let {
41
43
  children: renderView,
42
44
  renderWrapper,
43
45
  layout,
44
46
  collection,
45
47
  scrollDirection,
46
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
47
48
  isLoading,
48
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
49
49
  onLoadMore,
50
50
  persistedKeys,
51
51
  layoutOptions,
52
52
  ...otherProps
53
53
  } = props;
54
54
 
55
- let fallbackRef = useRef<HTMLDivElement>(undefined);
56
- ref = ref || fallbackRef;
55
+ let ref = useObjectRef(forwardedRef);
57
56
 
58
57
  let state = useVirtualizerState({
59
58
  layout,
60
59
  collection,
61
60
  renderView,
62
61
  onVisibleRectChange(rect) {
63
- ref.current.scrollLeft = rect.x;
64
- ref.current.scrollTop = rect.y;
62
+ if (ref.current) {
63
+ ref.current.scrollLeft = rect.x;
64
+ ref.current.scrollTop = rect.y;
65
+ }
65
66
  },
66
67
  persistedKeys,
67
68
  layoutOptions
@@ -83,12 +84,7 @@ function Virtualizer<T extends object, V extends ReactNode, O>(props: Virtualize
83
84
  {renderChildren(null, state.visibleViews, renderWrapper || defaultRenderWrapper)}
84
85
  </ScrollView>
85
86
  );
86
- }
87
-
88
- // forwardRef doesn't support generic parameters, so cast the result to the correct type
89
- // https://stackoverflow.com/questions/58469229/react-with-typescript-generics-while-using-react-forwardref
90
- const _Virtualizer = React.forwardRef(Virtualizer) as <T extends object, V, O>(props: VirtualizerProps<T, V, O> & {ref?: RefObject<HTMLDivElement | null>}) => ReactElement;
91
- export {_Virtualizer as Virtualizer};
87
+ }) as <T extends object, V, O>(props: VirtualizerProps<T, V, O> & {ref?: RefObject<HTMLDivElement | null>}) => ReactElement;
92
88
 
93
89
  function renderChildren<T extends object, V>(parent: ReusableView<T, V> | null, views: ReusableView<T, V>[], renderWrapper: RenderWrapper<T, V>) {
94
90
  return views.map(view => {
@@ -108,7 +104,7 @@ function defaultRenderWrapper<T extends object, V extends ReactNode>(
108
104
  return (
109
105
  <VirtualizerItem
110
106
  key={reusableView.key}
111
- layoutInfo={reusableView.layoutInfo}
107
+ layoutInfo={reusableView.layoutInfo!}
112
108
  virtualizer={reusableView.virtualizer}
113
109
  parent={parent?.layoutInfo}>
114
110
  {reusableView.rendered}
@@ -17,6 +17,7 @@ import {useLocale} from '@react-aria/i18n';
17
17
  import {useVirtualizerItem, VirtualizerItemOptions} from './useVirtualizerItem';
18
18
 
19
19
  interface VirtualizerItemProps extends Omit<VirtualizerItemOptions, 'ref'> {
20
+ layoutInfo: LayoutInfo,
20
21
  parent?: LayoutInfo | null,
21
22
  style?: CSSProperties,
22
23
  className?: string,
@@ -26,7 +27,7 @@ interface VirtualizerItemProps extends Omit<VirtualizerItemOptions, 'ref'> {
26
27
  export function VirtualizerItem(props: VirtualizerItemProps) {
27
28
  let {style, className, layoutInfo, virtualizer, parent, children} = props;
28
29
  let {direction} = useLocale();
29
- let ref = useRef(undefined);
30
+ let ref = useRef<HTMLDivElement | null>(null);
30
31
  useVirtualizerItem({
31
32
  layoutInfo,
32
33
  virtualizer,
@@ -57,7 +58,7 @@ export function layoutInfoToStyle(layoutInfo: LayoutInfo, dir: Direction, parent
57
58
  }
58
59
  }
59
60
 
60
- let rectStyles = {
61
+ let rectStyles: Record<string, number | undefined> = {
61
62
  // TODO: For layoutInfos that are sticky that have parents with overflow visible, their "top" will be relative to the to the nearest scrolling container
62
63
  // which WON'T be the parent since the parent has overflow visible. This means we shouldn't offset the height by the parent's position
63
64
  // Not 100% about this change here since it is quite ambigious what the scrolling container maybe and how its top is positioned with respect to the
@@ -82,7 +83,7 @@ export function layoutInfoToStyle(layoutInfo: LayoutInfo, dir: Direction, parent
82
83
  overflow: layoutInfo.allowOverflow ? 'visible' : 'hidden',
83
84
  opacity: layoutInfo.opacity,
84
85
  zIndex: layoutInfo.zIndex,
85
- transform: layoutInfo.transform,
86
+ transform: layoutInfo.transform ?? undefined,
86
87
  contain: 'size layout style',
87
88
  ...rectStyles
88
89
  };
@@ -20,20 +20,21 @@ interface IVirtualizer {
20
20
  }
21
21
 
22
22
  export interface VirtualizerItemOptions {
23
- layoutInfo: LayoutInfo,
23
+ layoutInfo: LayoutInfo | null,
24
24
  virtualizer: IVirtualizer,
25
25
  ref: RefObject<HTMLElement | null>
26
26
  }
27
27
 
28
28
  export function useVirtualizerItem(options: VirtualizerItemOptions) {
29
29
  let {layoutInfo, virtualizer, ref} = options;
30
+ let key = layoutInfo?.key;
30
31
 
31
32
  let updateSize = useCallback(() => {
32
- if (layoutInfo) {
33
+ if (key != null && ref.current) {
33
34
  let size = getSize(ref.current);
34
- virtualizer.updateItemSize(layoutInfo.key, size);
35
+ virtualizer.updateItemSize(key, size);
35
36
  }
36
- }, [virtualizer, layoutInfo?.key, ref]);
37
+ }, [virtualizer, key, ref]);
37
38
 
38
39
  useLayoutEffect(() => {
39
40
  if (layoutInfo?.estimatedSize) {