UNPKG

@wordpress/block-library

Version:
286 lines (281 loc) 9.24 kB
/** * External dependencies */ import clsx from 'clsx'; /** * WordPress dependencies */ import { memo, useMemo, useState } from '@wordpress/element'; import { useSelect } from '@wordpress/data'; import { __, _x } from '@wordpress/i18n'; import { BlockControls, BlockContextProvider, __experimentalUseBlockPreview as useBlockPreview, useBlockProps, useInnerBlocksProps, store as blockEditorStore } from '@wordpress/block-editor'; import { Spinner, ToolbarGroup } from '@wordpress/components'; import { store as coreStore } from '@wordpress/core-data'; import { list, grid } from '@wordpress/icons'; import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; const TEMPLATE = [['core/post-title'], ['core/post-date'], ['core/post-excerpt']]; function PostTemplateInnerBlocks({ classList }) { const innerBlocksProps = useInnerBlocksProps({ className: clsx('wp-block-post', classList) }, { template: TEMPLATE, __unstableDisableLayoutClassNames: true }); return /*#__PURE__*/_jsx("li", { ...innerBlocksProps }); } function PostTemplateBlockPreview({ blocks, blockContextId, classList, isHidden, setActiveBlockContextId }) { const blockPreviewProps = useBlockPreview({ blocks, props: { className: clsx('wp-block-post', classList) } }); const handleOnClick = () => { setActiveBlockContextId(blockContextId); }; const style = { display: isHidden ? 'none' : undefined }; return /*#__PURE__*/_jsx("li", { ...blockPreviewProps, tabIndex: 0 // eslint-disable-next-line jsx-a11y/no-noninteractive-element-to-interactive-role , role: "button", onClick: handleOnClick, onKeyPress: handleOnClick, style: style }); } const MemoizedPostTemplateBlockPreview = memo(PostTemplateBlockPreview); export default function PostTemplateEdit({ setAttributes, clientId, context: { query: { perPage, offset = 0, postType, order, orderBy, author, search, exclude, sticky, inherit, taxQuery, parents, pages, format, // We gather extra query args to pass to the REST API call. // This way extenders of Query Loop can add their own query args, // and have accurate previews in the editor. // Noting though that these args should either be supported by the // REST API or be handled by custom REST filters like `rest_{$this->post_type}_query`. ...restQueryArgs } = {}, templateSlug, previewPostType }, attributes: { layout }, __unstableLayoutClassNames }) { const { type: layoutType, columnCount = 3 } = layout || {}; const [activeBlockContextId, setActiveBlockContextId] = useState(); const { posts, blocks } = useSelect(select => { const { getEntityRecords, getTaxonomies } = select(coreStore); const { getBlocks } = select(blockEditorStore); const templateCategory = inherit && templateSlug?.startsWith('category-') && getEntityRecords('taxonomy', 'category', { context: 'view', per_page: 1, _fields: ['id'], slug: templateSlug.replace('category-', '') }); const templateTag = inherit && templateSlug?.startsWith('tag-') && getEntityRecords('taxonomy', 'post_tag', { context: 'view', per_page: 1, _fields: ['id'], slug: templateSlug.replace('tag-', '') }); const query = { offset: offset || 0, order, orderby: orderBy }; // There is no need to build the taxQuery if we inherit. if (taxQuery && !inherit) { const taxonomies = getTaxonomies({ type: postType, per_page: -1, context: 'view' }); // We have to build the tax query for the REST API and use as // keys the taxonomies `rest_base` with the `term ids` as values. const builtTaxQuery = Object.entries(taxQuery).reduce((accumulator, [taxonomySlug, terms]) => { const taxonomy = taxonomies?.find(({ slug }) => slug === taxonomySlug); if (taxonomy?.rest_base) { accumulator[taxonomy?.rest_base] = terms; } return accumulator; }, {}); if (!!Object.keys(builtTaxQuery).length) { Object.assign(query, builtTaxQuery); } } if (perPage) { query.per_page = perPage; } if (author) { query.author = author; } if (search) { query.search = search; } if (exclude?.length) { query.exclude = exclude; } if (parents?.length) { query.parent = parents; } if (format?.length) { query.format = format; } /* * Handle cases where sticky is set to `exclude` or `only`. * Which works as a `post__in/post__not_in` query for sticky posts. */ if (['exclude', 'only'].includes(sticky)) { query.sticky = sticky === 'only'; } // Empty string represents the default behavior of including sticky posts. if (['', 'ignore'].includes(sticky)) { // Remove any leftover sticky query parameter. delete query.sticky; query.ignore_sticky = sticky === 'ignore'; } // If `inherit` is truthy, adjust conditionally the query to create a better preview. let currentPostType = postType; if (inherit) { // Change the post-type if needed. if (templateSlug?.startsWith('archive-')) { query.postType = templateSlug.replace('archive-', ''); currentPostType = query.postType; } else if (templateCategory) { query.categories = templateCategory[0]?.id; } else if (templateTag) { query.tags = templateTag[0]?.id; } else if (templateSlug?.startsWith('taxonomy-post_format')) { // Get the post format slug from the template slug by removing the prefix. query.format = templateSlug.replace('taxonomy-post_format-post-format-', ''); } } // When we preview Query Loop blocks we should prefer the current // block's postType, which is passed through block context. const usedPostType = previewPostType || currentPostType; return { posts: getEntityRecords('postType', usedPostType, { ...query, ...restQueryArgs }), blocks: getBlocks(clientId) }; }, [perPage, offset, order, orderBy, clientId, author, search, postType, exclude, sticky, inherit, templateSlug, taxQuery, parents, format, restQueryArgs, previewPostType]); const blockContexts = useMemo(() => posts?.map(post => { var _post$class_list; return { postType: post.type, postId: post.id, classList: (_post$class_list = post.class_list) !== null && _post$class_list !== void 0 ? _post$class_list : '' }; }), [posts]); const blockProps = useBlockProps({ className: clsx(__unstableLayoutClassNames, { [`columns-${columnCount}`]: layoutType === 'grid' && columnCount // Ensure column count is flagged via classname for backwards compatibility. }) }); if (!posts) { return /*#__PURE__*/_jsx("p", { ...blockProps, children: /*#__PURE__*/_jsx(Spinner, {}) }); } if (!posts.length) { return /*#__PURE__*/_jsxs("p", { ...blockProps, children: [" ", __('No results found.')] }); } const setDisplayLayout = newDisplayLayout => setAttributes({ layout: { ...layout, ...newDisplayLayout } }); const displayLayoutControls = [{ icon: list, title: _x('List view', 'Post template block display setting'), onClick: () => setDisplayLayout({ type: 'default' }), isActive: layoutType === 'default' || layoutType === 'constrained' }, { icon: grid, title: _x('Grid view', 'Post template block display setting'), onClick: () => setDisplayLayout({ type: 'grid', columnCount }), isActive: layoutType === 'grid' }]; // To avoid flicker when switching active block contexts, a preview is rendered // for each block context, but the preview for the active block context is hidden. // This ensures that when it is displayed again, the cached rendering of the // block preview is used, instead of having to re-render the preview from scratch. return /*#__PURE__*/_jsxs(_Fragment, { children: [/*#__PURE__*/_jsx(BlockControls, { children: /*#__PURE__*/_jsx(ToolbarGroup, { controls: displayLayoutControls }) }), /*#__PURE__*/_jsx("ul", { ...blockProps, children: blockContexts && blockContexts.map(blockContext => /*#__PURE__*/_jsxs(BlockContextProvider, { value: blockContext, children: [blockContext.postId === (activeBlockContextId || blockContexts[0]?.postId) ? /*#__PURE__*/_jsx(PostTemplateInnerBlocks, { classList: blockContext.classList }) : null, /*#__PURE__*/_jsx(MemoizedPostTemplateBlockPreview, { blocks: blocks, blockContextId: blockContext.postId, classList: blockContext.classList, setActiveBlockContextId: setActiveBlockContextId, isHidden: blockContext.postId === (activeBlockContextId || blockContexts[0]?.postId) })] }, blockContext.postId)) })] }); } //# sourceMappingURL=edit.js.map