@wordpress/block-editor
Version:
118 lines (115 loc) • 4.29 kB
JavaScript
/**
* WordPress dependencies
*/
import { useEffect, useState, useRef } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
/**
* Internal dependencies
*/
import { store as blockEditorStore } from '../../../store';
import { unlock } from '../../../lock-unlock';
/** @typedef {import('../../../store/actions').InserterMediaRequest} InserterMediaRequest */
/** @typedef {import('../../../store/actions').InserterMediaItem} InserterMediaItem */
/**
* Fetches media items based on the provided category.
* Each media category is responsible for providing a `fetch` function.
*
* @param {Object} category The media category to fetch results for.
* @param {InserterMediaRequest} query The query args to use for the request.
* @return {InserterMediaItem[]} The media results.
*/
export function useMediaResults(category, query = {}) {
const [mediaList, setMediaList] = useState();
const [isLoading, setIsLoading] = useState(false);
// We need to keep track of the last request made because
// multiple request can be fired without knowing the order
// of resolution, and we need to ensure we are showing
// the results of the last request.
// In the future we could use AbortController to cancel previous
// requests, but we don't for now as it involves adding support
// for this to `core-data` package.
const lastRequestRef = useRef();
useEffect(() => {
(async () => {
const key = JSON.stringify({
category: category.name,
...query
});
lastRequestRef.current = key;
setIsLoading(true);
setMediaList([]); // Empty the previous results.
const _media = await category.fetch?.(query);
if (key === lastRequestRef.current) {
setMediaList(_media);
setIsLoading(false);
}
})();
}, [category.name, ...Object.values(query)]);
return {
mediaList,
isLoading
};
}
export function useMediaCategories(rootClientId) {
const [categories, setCategories] = useState([]);
const inserterMediaCategories = useSelect(select => unlock(select(blockEditorStore)).getInserterMediaCategories(), []);
const {
canInsertImage,
canInsertVideo,
canInsertAudio
} = useSelect(select => {
const {
canInsertBlockType
} = select(blockEditorStore);
return {
canInsertImage: canInsertBlockType('core/image', rootClientId),
canInsertVideo: canInsertBlockType('core/video', rootClientId),
canInsertAudio: canInsertBlockType('core/audio', rootClientId)
};
}, [rootClientId]);
useEffect(() => {
(async () => {
const _categories = [];
// If `inserterMediaCategories` is not defined in
// block editor settings, do not show any media categories.
if (!inserterMediaCategories) {
return;
}
// Loop through categories to check if they have at least one media item.
const categoriesHaveMedia = new Map(await Promise.all(inserterMediaCategories.map(async category => {
// Some sources are external and we don't need to make a request.
if (category.isExternalResource) {
return [category.name, true];
}
let results = [];
try {
results = await category.fetch({
per_page: 1
});
} catch (e) {
// If the request fails, we shallow the error and just don't show
// the category, in order to not break the media tab.
}
return [category.name, !!results.length];
})));
// We need to filter out categories that don't have any media items or
// whose corresponding block type is not allowed to be inserted, based
// on the category's `mediaType`.
const canInsertMediaType = {
image: canInsertImage,
video: canInsertVideo,
audio: canInsertAudio
};
inserterMediaCategories.forEach(category => {
if (canInsertMediaType[category.mediaType] && categoriesHaveMedia.get(category.name)) {
_categories.push(category);
}
});
if (!!_categories.length) {
setCategories(_categories);
}
})();
}, [canInsertImage, canInsertVideo, canInsertAudio, inserterMediaCategories]);
return categories;
}
//# sourceMappingURL=hooks.js.map