Build NapCat Artifacts / Windows Loader Test (push) Canceled after 0s
Build NapCat Artifacts / Type Check & Test (push) Canceled after 0s
Build NapCat Artifacts / Build NapCat.Framework (push) Canceled after 0s
Build NapCat Artifacts / Build NapCat.Shell (push) Canceled after 0s
121 lines
3.8 KiB
Plaintext
121 lines
3.8 KiB
Plaintext
/*
|
|
* Copyright 2020 Adobe. All rights reserved.
|
|
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
* governing permissions and limitations under the License.
|
|
*/
|
|
|
|
import {Collection, Key} from '@react-types/shared';
|
|
import {InvalidationContext} from './types';
|
|
import {Layout} from './Layout';
|
|
import React, {useCallback, useMemo, useRef, useState} from 'react';
|
|
import {Rect} from './Rect';
|
|
import {ReusableView} from './ReusableView';
|
|
import {Size} from './Size';
|
|
import {Virtualizer} from './Virtualizer';
|
|
|
|
// During SSR, React emits a warning when calling useLayoutEffect.
|
|
// Since neither useLayoutEffect nor useEffect run on the server,
|
|
// we can suppress this by replace it with a noop on the server.
|
|
export const useLayoutEffect: typeof React.useLayoutEffect = typeof document !== 'undefined'
|
|
? React.useLayoutEffect
|
|
: () => {};
|
|
|
|
interface VirtualizerProps<T extends object, V, O> {
|
|
renderView(type: string, content: T | null): V,
|
|
layout: Layout<T>,
|
|
collection: Collection<T>,
|
|
onVisibleRectChange(rect: Rect): void,
|
|
persistedKeys?: Set<Key> | null,
|
|
layoutOptions?: O
|
|
}
|
|
|
|
export interface VirtualizerState<T extends object, V> {
|
|
visibleViews: ReusableView<T, V>[],
|
|
setVisibleRect: (rect: Rect) => void,
|
|
contentSize: Size,
|
|
virtualizer: Virtualizer<T, V>,
|
|
isScrolling: boolean,
|
|
startScrolling: () => void,
|
|
endScrolling: () => void
|
|
}
|
|
|
|
export function useVirtualizerState<T extends object, V, O = any>(opts: VirtualizerProps<T, V, O>): VirtualizerState<T, V> {
|
|
let [visibleRect, setVisibleRect] = useState(new Rect(0, 0, 0, 0));
|
|
let [isScrolling, setScrolling] = useState(false);
|
|
let [invalidationContext, setInvalidationContext] = useState<InvalidationContext>({});
|
|
let visibleRectChanged = useRef(false);
|
|
let [virtualizer] = useState(() => new Virtualizer<T, V>({
|
|
collection: opts.collection,
|
|
layout: opts.layout,
|
|
delegate: {
|
|
setVisibleRect(rect) {
|
|
setVisibleRect(rect);
|
|
visibleRectChanged.current = true;
|
|
},
|
|
// TODO: should changing these invalidate the entire cache?
|
|
renderView: opts.renderView,
|
|
invalidate: setInvalidationContext
|
|
}
|
|
}));
|
|
|
|
// onVisibleRectChange must be called from an effect, not during render.
|
|
useLayoutEffect(() => {
|
|
if (visibleRectChanged.current) {
|
|
visibleRectChanged.current = false;
|
|
opts.onVisibleRectChange(visibleRect);
|
|
}
|
|
});
|
|
|
|
let mergedInvalidationContext = useMemo(() => {
|
|
if (opts.layoutOptions != null) {
|
|
return {...invalidationContext, layoutOptions: opts.layoutOptions};
|
|
}
|
|
return invalidationContext;
|
|
}, [invalidationContext, opts.layoutOptions]);
|
|
|
|
let visibleViews = virtualizer.render({
|
|
layout: opts.layout,
|
|
collection: opts.collection,
|
|
persistedKeys: opts.persistedKeys,
|
|
layoutOptions: opts.layoutOptions,
|
|
visibleRect,
|
|
invalidationContext: mergedInvalidationContext,
|
|
isScrolling
|
|
});
|
|
|
|
let contentSize = virtualizer.contentSize;
|
|
|
|
let startScrolling = useCallback(() => {
|
|
setScrolling(true);
|
|
}, []);
|
|
let endScrolling = useCallback(() => {
|
|
setScrolling(false);
|
|
}, []);
|
|
|
|
let state = useMemo(() => ({
|
|
virtualizer,
|
|
visibleViews,
|
|
setVisibleRect,
|
|
contentSize,
|
|
isScrolling,
|
|
startScrolling,
|
|
endScrolling
|
|
}), [
|
|
virtualizer,
|
|
visibleViews,
|
|
setVisibleRect,
|
|
contentSize,
|
|
isScrolling,
|
|
startScrolling,
|
|
endScrolling
|
|
]);
|
|
|
|
return state;
|
|
}
|