@wordpress/components
Version:
UI components for WordPress.
140 lines (134 loc) • 4.18 kB
JavaScript
/**
* External dependencies
*/
import { ActivityIndicator, FlatList, View } from 'react-native';
/**
* WordPress dependencies
*/
import { debounce } from '@wordpress/compose';
import { useState, useEffect, useRef } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
/**
* Internal dependencies
*/
import styles from './styles.scss';
import BottomSheet from '../bottom-sheet';
import { BottomSheetConsumer } from '../bottom-sheet/bottom-sheet-context';
import { jsx as _jsx } from "react/jsx-runtime";
const PER_PAGE = 20;
const REQUEST_DEBOUNCE_DELAY = 400;
const MINIMUM_QUERY_SIZE = 2;
const meetsThreshold = query => MINIMUM_QUERY_SIZE <= query.length;
export default function LinkPickerResults({
query,
onLinkPicked,
directEntry
}) {
const [links, setLinks] = useState([directEntry]);
const [hasAllSuggestions, setHasAllSuggestions] = useState(false);
const nextPage = useRef(1);
const pendingRequest = useRef();
const clearRequest = () => {
pendingRequest.current = null;
};
// A stable debounced function to fetch suggestions and append.
const {
fetchMoreSuggestions
} = useSelect(select => {
const {
getSettings
} = select('core/block-editor');
const fetchLinkSuggestions = async ({
search
}) => {
if (meetsThreshold(search)) {
return await getSettings().__experimentalFetchLinkSuggestions(search, {
page: nextPage.current,
type: 'post',
perPage: PER_PAGE
});
}
};
const fetchMore = async ({
query: search,
links: currentSuggestions
}) => {
// Return early if we've already detected the end of data or we are
// already awaiting a response.
if (hasAllSuggestions || pendingRequest.current) {
return;
}
const request = fetchLinkSuggestions({
search
});
pendingRequest.current = request;
const suggestions = await request;
// Only update links for the most recent request.
if (suggestions && request === pendingRequest.current) {
// Since we don't have the response header, we check if the results
// are truncated to determine we've reached the end.
if (suggestions.length < PER_PAGE) {
setHasAllSuggestions(true);
}
setLinks([...currentSuggestions, ...suggestions]);
nextPage.current++;
}
clearRequest();
};
return {
fetchMoreSuggestions: debounce(fetchMore, REQUEST_DEBOUNCE_DELAY)
};
// Not adding dependencies for now, to avoid introducing a regression
// (see https://github.com/WordPress/gutenberg/pull/23922#discussion_r1170634879).
}, []);
// Prevent setting state when unmounted.
useEffect(() => clearRequest, []);
// Any time the query changes, we reset pagination.
useEffect(() => {
clearRequest();
nextPage.current = 1;
setHasAllSuggestions(false);
setLinks([directEntry]);
fetchMoreSuggestions({
query,
links: [directEntry]
});
// See https://github.com/WordPress/gutenberg/pull/41166
}, [query]);
const onEndReached = () => fetchMoreSuggestions({
query,
links
});
const spinner = !hasAllSuggestions && meetsThreshold(query) && /*#__PURE__*/_jsx(View, {
style: styles.spinner,
testID: "link-picker-loading",
children: /*#__PURE__*/_jsx(ActivityIndicator, {
animating: true
})
});
return /*#__PURE__*/_jsx(BottomSheetConsumer, {
children: ({
listProps
}) => /*#__PURE__*/_jsx(FlatList, {
data: links,
keyboardShouldPersistTaps: "always",
renderItem: ({
item
}) => /*#__PURE__*/_jsx(BottomSheet.LinkSuggestionItemCell, {
suggestion: item,
onLinkPicked: onLinkPicked
}),
keyExtractor: ({
url,
type
}) => `${url}-${type}`,
onEndReached: onEndReached,
onEndReachedThreshold: 0.1,
initialNumToRender: PER_PAGE,
ListFooterComponent: spinner,
...listProps,
contentContainerStyle: [...listProps.contentContainerStyle, styles.list]
})
});
}
//# sourceMappingURL=link-picker-results.native.js.map