feat: Initial clean release of CHM
一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
这个提交包含在:
@@ -0,0 +1,127 @@
|
||||
import * as React from 'react';
|
||||
import { Ref, useRef, useImperativeHandle, useState, useCallback } from 'react';
|
||||
import { LayoutChangeEvent, NativeScrollEvent, NativeSyntheticEvent, ScrollView, ScrollViewProps, View, ViewProps } from 'react-native';
|
||||
|
||||
interface RenderEvent<T> {
|
||||
item: T;
|
||||
index: number;
|
||||
}
|
||||
|
||||
interface ScrollToOptions {
|
||||
index: number;
|
||||
viewPosition: number;
|
||||
animated: boolean;
|
||||
}
|
||||
|
||||
export interface NestableFlatListControl {
|
||||
scrollToIndex(options: ScrollToOptions): void;
|
||||
}
|
||||
|
||||
interface CellRendererProps<T> {
|
||||
index: number;
|
||||
item: T;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
// For compatibility, these props should be mostly compatible with the
|
||||
// native FlatList props:
|
||||
interface Props<T> extends ScrollViewProps {
|
||||
ref: Ref<NestableFlatListControl>;
|
||||
data: T[];
|
||||
itemHeight: number;
|
||||
CellRendererComponent?: React.ComponentType<CellRendererProps<T>>;
|
||||
renderItem: (event: RenderEvent<T>)=> React.ReactNode;
|
||||
keyExtractor: (item: T)=> string;
|
||||
extraData: unknown;
|
||||
|
||||
// Additional props.
|
||||
// The contentWrapperProps can be used to improve accessibility by
|
||||
// applying certain content roles to the <View> that directly contains
|
||||
// the list's content. At least on web, applying these props directly to the ScrollView may
|
||||
// not work due to additional <View>s added by React Native.
|
||||
contentWrapperProps?: ViewProps;
|
||||
}
|
||||
|
||||
// This component allows working around restrictions on nesting React Native's built-in
|
||||
// <FlatList> within <ScrollView>s. For the most part, this component's interface should
|
||||
// be compatible with the <FlatList> API.
|
||||
//
|
||||
// See https://github.com/facebook/react-native/issues/31697.
|
||||
const NestableFlatList = function<T>({
|
||||
ref,
|
||||
itemHeight,
|
||||
renderItem,
|
||||
keyExtractor,
|
||||
data,
|
||||
CellRendererComponent = React.Fragment,
|
||||
contentWrapperProps,
|
||||
...rest
|
||||
}: Props<T>) {
|
||||
const scrollViewRef = useRef<ScrollView|null>(null);
|
||||
const [scroll, setScroll] = useState(0);
|
||||
const [listHeight, setListHeight] = useState(0);
|
||||
|
||||
useImperativeHandle(ref, () => {
|
||||
return {
|
||||
scrollToIndex: ({ index, animated, viewPosition }) => {
|
||||
const offset = Math.max(0, index * itemHeight - viewPosition * listHeight);
|
||||
scrollViewRef.current.scrollTo({
|
||||
y: offset,
|
||||
animated,
|
||||
});
|
||||
// onScroll events don't seem to be sent when scrolling with .scrollTo.
|
||||
// The scroll offset needs to be updated manually:
|
||||
setScroll(offset);
|
||||
},
|
||||
};
|
||||
}, [itemHeight, listHeight]);
|
||||
|
||||
const onScroll = useCallback((event: NativeSyntheticEvent<NativeScrollEvent>) => {
|
||||
setScroll(event.nativeEvent.contentOffset.y);
|
||||
}, []);
|
||||
const onLayout = useCallback((event: LayoutChangeEvent) => {
|
||||
setListHeight(event.nativeEvent.layout.height);
|
||||
}, []);
|
||||
|
||||
const bufferSize = 10;
|
||||
const visibleStartIndex = Math.min(Math.floor(scroll / itemHeight), data.length);
|
||||
const visibleEndIndex = Math.ceil((scroll + listHeight) / itemHeight);
|
||||
const startIndex = Math.max(0, visibleStartIndex - bufferSize);
|
||||
const maximumIndex = data.length - 1;
|
||||
const endIndex = Math.min(visibleEndIndex + bufferSize, maximumIndex);
|
||||
const paddingTop = startIndex * itemHeight;
|
||||
const paddingBottom = (maximumIndex - endIndex) * itemHeight;
|
||||
|
||||
const renderVisibleItems = () => {
|
||||
const result: React.ReactNode[] = [];
|
||||
|
||||
for (let i = startIndex; i <= endIndex; i++) {
|
||||
result.push(
|
||||
<CellRendererComponent
|
||||
index={i}
|
||||
item={data[i]}
|
||||
key={keyExtractor(data[i])}
|
||||
>
|
||||
{renderItem({ item: data[i], index: i })}
|
||||
</CellRendererComponent>,
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
return <ScrollView
|
||||
ref={scrollViewRef}
|
||||
onScroll={onScroll}
|
||||
onLayout={onLayout}
|
||||
{...rest}
|
||||
>
|
||||
<View {...contentWrapperProps}>
|
||||
<View style={{ height: paddingTop }}/>
|
||||
{renderVisibleItems()}
|
||||
<View style={{ height: paddingBottom }}/>
|
||||
</View>
|
||||
</ScrollView>;
|
||||
};
|
||||
|
||||
export default NestableFlatList;
|
||||
在新工单中引用
屏蔽一个用户