@wordpress/block-library
Version:
Block library for the WordPress editor.
135 lines (120 loc) • 4.33 kB
JavaScript
import { createElement } from "@wordpress/element";
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { FormTokenField } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
import { useState, useEffect, useMemo } from '@wordpress/element';
import { useDebounce } from '@wordpress/compose';
/**
* Internal dependencies
*/
import { getEntitiesInfo, mapToIHasNameAndId } from '../../utils';
const EMPTY_ARRAY = [];
const BASE_QUERY = {
order: 'asc',
_fields: 'id,title',
context: 'view'
};
function ParentControl(_ref) {
let {
parents,
postType,
onChange
} = _ref;
const [search, setSearch] = useState('');
const [value, setValue] = useState(EMPTY_ARRAY);
const [suggestions, setSuggestions] = useState(EMPTY_ARRAY);
const debouncedSearch = useDebounce(setSearch, 250);
const {
searchResults,
searchHasResolved
} = useSelect(select => {
if (!search) {
return {
searchResults: EMPTY_ARRAY,
searchHasResolved: true
};
}
const {
getEntityRecords,
hasFinishedResolution
} = select(coreStore);
const selectorArgs = ['postType', postType, { ...BASE_QUERY,
search,
orderby: 'relevance',
exclude: parents,
per_page: 20
}];
return {
searchResults: getEntityRecords(...selectorArgs),
searchHasResolved: hasFinishedResolution('getEntityRecords', selectorArgs)
};
}, [search, parents]);
const currentParents = useSelect(select => {
if (!(parents !== null && parents !== void 0 && parents.length)) return EMPTY_ARRAY;
const {
getEntityRecords
} = select(coreStore);
return getEntityRecords('postType', postType, { ...BASE_QUERY,
include: parents,
per_page: parents.length
});
}, [parents]); // Update the `value` state only after the selectors are resolved
// to avoid emptying the input when we're changing parents.
useEffect(() => {
if (!(parents !== null && parents !== void 0 && parents.length)) {
setValue(EMPTY_ARRAY);
}
if (!(currentParents !== null && currentParents !== void 0 && currentParents.length)) return;
const currentParentsInfo = getEntitiesInfo(mapToIHasNameAndId(currentParents, 'title.rendered')); // Returns only the existing entity ids. This prevents the component
// from crashing in the editor, when non existing ids are provided.
const sanitizedValue = parents.reduce((accumulator, id) => {
const entity = currentParentsInfo.mapById[id];
if (entity) {
accumulator.push({
id,
value: entity.name
});
}
return accumulator;
}, []);
setValue(sanitizedValue);
}, [parents, currentParents]);
const entitiesInfo = useMemo(() => {
if (!(searchResults !== null && searchResults !== void 0 && searchResults.length)) return EMPTY_ARRAY;
return getEntitiesInfo(mapToIHasNameAndId(searchResults, 'title.rendered'));
}, [searchResults]); // Update suggestions only when the query has resolved.
useEffect(() => {
if (!searchHasResolved) return;
setSuggestions(entitiesInfo.names);
}, [entitiesInfo.names, searchHasResolved]);
const getIdByValue = (entitiesMappedByName, entity) => {
var _entitiesMappedByName;
const id = (entity === null || entity === void 0 ? void 0 : entity.id) || (entitiesMappedByName === null || entitiesMappedByName === void 0 ? void 0 : (_entitiesMappedByName = entitiesMappedByName[entity]) === null || _entitiesMappedByName === void 0 ? void 0 : _entitiesMappedByName.id);
if (id) return id;
};
const onParentChange = newValue => {
const ids = Array.from(newValue.reduce((accumulator, entity) => {
// Verify that new values point to existing entities.
const id = getIdByValue(entitiesInfo.mapByName, entity);
if (id) accumulator.add(id);
return accumulator;
}, new Set()));
setSuggestions(EMPTY_ARRAY);
onChange({
parents: ids
});
};
return createElement(FormTokenField, {
label: __('Parents'),
value: value,
onInputChange: debouncedSearch,
suggestions: suggestions,
onChange: onParentChange
});
}
export default ParentControl;
//# sourceMappingURL=parent-control.js.map