Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions packages/@react-spectrum/list/stories/ListView.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -517,3 +517,32 @@ function Demo(props) {
</ListView>
);
}

const manyItems = [];
for (let i = 0; i < 500; i++) {manyItems.push({key: i, name: `item ${i}`});}

function DisplayNoneComponent(args) {
const [isDisplay, setIsDisplay] = useState(false);

return (
<>
<Button variant="primary" onPress={() => setIsDisplay(prev => !prev)}>Toggle ListView display</Button>
<div style={!isDisplay ? {display: 'none'} : null}>
<ListView aria-label="Many items" items={manyItems} width="300px" height="200px" {...args}>
{(item: any) => (
<Item key={item.key} textValue={item.name}>
<Text>
{item.name}
</Text>
</Item>
)}
</ListView>
</div>
</>
);
}

export const DisplayNone: ListViewStory = {
render: (args) => <DisplayNoneComponent {...args} />,
name: 'display: none with many items'
};
24 changes: 24 additions & 0 deletions packages/@react-spectrum/list/test/ListView.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1664,4 +1664,28 @@ describe('ListView', function () {
});
});
});

describe('height 0', () => {

it('should render and not infinite loop', function () {
offsetWidth = jest.spyOn(window.HTMLElement.prototype, 'clientWidth', 'get').mockImplementation(() => 0);
offsetHeight = jest.spyOn(window.HTMLElement.prototype, 'clientHeight', 'get').mockImplementation(() => 0);
scrollHeight = jest.spyOn(window.HTMLElement.prototype, 'scrollHeight', 'get').mockImplementation(() => 0);
let tree = render(
<ListView
width="250px"
height="60px"
aria-label="List"
data-testid="test"
items={[...Array(20).keys()].map(k => ({key: k, name: `Item ${k}`}))}>
{item => <Item>{item.name}</Item>}
</ListView>
);
let grid = tree.getByRole('grid');
act(() => {
jest.runAllTimers();
});
expect(grid.firstChild).toBeEmptyDOMElement();
});
});
});
2 changes: 1 addition & 1 deletion packages/@react-stately/virtualizer/src/OverscanManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export class OverscanManager {
private startTime = 0;
private velocity = new Point(0, 0);
private visibleRect = new Rect();

setVisibleRect(rect: Rect) {
let time = performance.now() - this.startTime;
if (time < 500) {
Expand Down
10 changes: 5 additions & 5 deletions packages/@react-stately/virtualizer/src/Virtualizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import {Size} from './Size';

/**
* The Virtualizer class renders a scrollable collection of data using customizable layouts.
* It supports very large collections by only rendering visible views to the DOM, reusing
* them as you scroll. Virtualizer can present any type of view, including non-item views
* It supports very large collections by only rendering visible views to the DOM, reusing
* them as you scroll. Virtualizer can present any type of view, including non-item views
* such as section headers and footers.
*
* Virtualizer uses {@link Layout} objects to compute what views should be visible, and how
Expand Down Expand Up @@ -133,7 +133,7 @@ export class Virtualizer<T extends object, V, W> {
*/
keyAtPoint(point: Point): Key | null {
let rect = new Rect(point.x, point.y, 1, 1);
let layoutInfos = this.layout.getVisibleLayoutInfos(rect);
let layoutInfos = rect.area === 0 ? [] : this.layout.getVisibleLayoutInfos(rect);

// Layout may return multiple layout infos in the case of
// persisted keys, so find the first one that actually intersects.
Expand Down Expand Up @@ -180,7 +180,7 @@ export class Virtualizer<T extends object, V, W> {
rect = this._overscanManager.getOverscannedRect();
}

let layoutInfos = this.layout.getVisibleLayoutInfos(rect);
let layoutInfos = rect.area === 0 ? [] : this.layout.getVisibleLayoutInfos(rect);
let map = new Map;
for (let layoutInfo of layoutInfos) {
map.set(layoutInfo.key, layoutInfo);
Expand Down Expand Up @@ -273,7 +273,7 @@ export class Virtualizer<T extends object, V, W> {
if (!this.visibleRect.equals(opts.visibleRect)) {
this._overscanManager.setVisibleRect(opts.visibleRect);
let shouldInvalidate = this.layout.shouldInvalidate(opts.visibleRect, this.visibleRect);

if (shouldInvalidate) {
offsetChanged = !opts.visibleRect.pointEquals(this.visibleRect);
sizeChanged = !opts.visibleRect.sizeEquals(this.visibleRect);
Expand Down