@wordpress/block-library
Version:
Block library for the WordPress editor.
274 lines (263 loc) • 9.3 kB
JavaScript
/**
* WordPress dependencies
*/
import { useState, memo } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import { BlockContextProvider, useBlockProps, useInnerBlocksProps, store as blockEditorStore, __experimentalUseBlockPreview as useBlockPreview } from '@wordpress/block-editor';
import { Spinner } from '@wordpress/components';
import { store as coreStore } from '@wordpress/core-data';
/**
* Internal dependencies
*/
import { useCommentQueryArgs, useCommentTree } from './hooks';
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
const TEMPLATE = [['core/avatar'], ['core/comment-author-name'], ['core/comment-date'], ['core/comment-content'], ['core/comment-reply-link'], ['core/comment-edit-link']];
/**
* Function that returns a comment structure that will be rendered with default placehoders.
*
* Each comment has a `commentId` property that is always a negative number in
* case of the placeholders. This is to ensure that the comment does not
* conflict with the actual (real) comments.
*
* @param {Object} settings Discussion Settings.
* @param {number} [settings.perPage] - Comments per page setting or block attribute.
* @param {boolean} [settings.pageComments] - Enable break comments into pages setting.
* @param {boolean} [settings.threadComments] - Enable threaded (nested) comments setting.
* @param {number} [settings.threadCommentsDepth] - Level deep of threaded comments.
*
* @typedef {{id: null, children: EmptyComment[]}} EmptyComment
* @return {EmptyComment[]} Inner blocks of the Comment Template
*/
const getCommentsPlaceholder = ({
perPage,
pageComments,
threadComments,
threadCommentsDepth
}) => {
// Limit commentsDepth to 3
const commentsDepth = !threadComments ? 1 : Math.min(threadCommentsDepth, 3);
const buildChildrenComment = commentsLevel => {
// Render children comments until commentsDepth is reached
if (commentsLevel < commentsDepth) {
const nextLevel = commentsLevel + 1;
return [{
commentId: -(commentsLevel + 3),
children: buildChildrenComment(nextLevel)
}];
}
return [];
};
// Add the first comment and its children
const placeholderComments = [{
commentId: -1,
children: buildChildrenComment(1)
}];
// Add a second comment unless the break comments setting is active and set to less than 2, and there is one nested comment max
if ((!pageComments || perPage >= 2) && commentsDepth < 3) {
placeholderComments.push({
commentId: -2,
children: []
});
}
// Add a third comment unless the break comments setting is active and set to less than 3, and there aren't nested comments
if ((!pageComments || perPage >= 3) && commentsDepth < 2) {
placeholderComments.push({
commentId: -3,
children: []
});
}
// In case that the value is set but larger than 3 we truncate it to 3.
return placeholderComments;
};
/**
* Component which renders the inner blocks of the Comment Template.
*
* @param {Object} props Component props.
* @param {Array} [props.comment] - A comment object.
* @param {Array} [props.activeCommentId] - The ID of the comment that is currently active.
* @param {Array} [props.setActiveCommentId] - The setter for activeCommentId.
* @param {Array} [props.firstCommentId] - ID of the first comment in the array.
* @param {Array} [props.blocks] - Array of blocks returned from
* getBlocks() in parent .
* @return {Element} Inner blocks of the Comment Template
*/
function CommentTemplateInnerBlocks({
comment,
activeCommentId,
setActiveCommentId,
firstCommentId,
blocks
}) {
const {
children,
...innerBlocksProps
} = useInnerBlocksProps({}, {
template: TEMPLATE
});
return /*#__PURE__*/_jsxs("li", {
...innerBlocksProps,
children: [comment.commentId === (activeCommentId || firstCommentId) ? children : null, /*#__PURE__*/_jsx(MemoizedCommentTemplatePreview, {
blocks: blocks,
commentId: comment.commentId,
setActiveCommentId: setActiveCommentId,
isHidden: comment.commentId === (activeCommentId || firstCommentId)
}), comment?.children?.length > 0 ? /*#__PURE__*/_jsx(CommentsList, {
comments: comment.children,
activeCommentId: activeCommentId,
setActiveCommentId: setActiveCommentId,
blocks: blocks,
firstCommentId: firstCommentId
}) : null]
});
}
const CommentTemplatePreview = ({
blocks,
commentId,
setActiveCommentId,
isHidden
}) => {
const blockPreviewProps = useBlockPreview({
blocks
});
const handleOnClick = () => {
setActiveCommentId(commentId);
};
// We have to hide the preview block if the `comment` props points to
// the currently active block!
// Or, to put it differently, every preview block is visible unless it is the
// currently active block - in this case we render its inner blocks.
const style = {
display: isHidden ? 'none' : undefined
};
return /*#__PURE__*/_jsx("div", {
...blockPreviewProps,
tabIndex: 0,
role: "button",
style: style
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-to-interactive-role
,
onClick: handleOnClick,
onKeyPress: handleOnClick
});
};
const MemoizedCommentTemplatePreview = memo(CommentTemplatePreview);
/**
* Component that renders a list of (nested) comments. It is called recursively.
*
* @param {Object} props Component props.
* @param {Array} [props.comments] - Array of comment objects.
* @param {Array} [props.blockProps] - Props from parent's `useBlockProps()`.
* @param {Array} [props.activeCommentId] - The ID of the comment that is currently active.
* @param {Array} [props.setActiveCommentId] - The setter for activeCommentId.
* @param {Array} [props.blocks] - Array of blocks returned from getBlocks() in parent.
* @param {Object} [props.firstCommentId] - The ID of the first comment in the array of
* comment objects.
* @return {Element} List of comments.
*/
const CommentsList = ({
comments,
blockProps,
activeCommentId,
setActiveCommentId,
blocks,
firstCommentId
}) => /*#__PURE__*/_jsx("ol", {
...blockProps,
children: comments && comments.map(({
commentId,
...comment
}, index) => /*#__PURE__*/_jsx(BlockContextProvider, {
value: {
// If the commentId is negative it means that this comment is a
// "placeholder" and that the block is most likely being used in the
// site editor. In this case, we have to set the commentId to `null`
// because otherwise the (non-existent) comment with a negative ID
// would be requested from the REST API.
commentId: commentId < 0 ? null : commentId
},
children: /*#__PURE__*/_jsx(CommentTemplateInnerBlocks, {
comment: {
commentId,
...comment
},
activeCommentId: activeCommentId,
setActiveCommentId: setActiveCommentId,
blocks: blocks,
firstCommentId: firstCommentId
})
}, comment.commentId || index))
});
export default function CommentTemplateEdit({
clientId,
context: {
postId
}
}) {
const blockProps = useBlockProps();
const [activeCommentId, setActiveCommentId] = useState();
const {
commentOrder,
threadCommentsDepth,
threadComments,
commentsPerPage,
pageComments
} = useSelect(select => {
const {
getSettings
} = select(blockEditorStore);
return getSettings().__experimentalDiscussionSettings;
});
const commentQuery = useCommentQueryArgs({
postId
});
const {
topLevelComments,
blocks
} = useSelect(select => {
const {
getEntityRecords
} = select(coreStore);
const {
getBlocks
} = select(blockEditorStore);
return {
// Request only top-level comments. Replies are embedded.
topLevelComments: commentQuery ? getEntityRecords('root', 'comment', commentQuery) : null,
blocks: getBlocks(clientId)
};
}, [clientId, commentQuery]);
// Generate a tree structure of comment IDs.
let commentTree = useCommentTree(
// Reverse the order of top comments if needed.
commentOrder === 'desc' && topLevelComments ? [...topLevelComments].reverse() : topLevelComments);
if (!topLevelComments) {
return /*#__PURE__*/_jsx("p", {
...blockProps,
children: /*#__PURE__*/_jsx(Spinner, {})
});
}
if (!postId) {
commentTree = getCommentsPlaceholder({
perPage: commentsPerPage,
pageComments,
threadComments,
threadCommentsDepth
});
}
if (!commentTree.length) {
return /*#__PURE__*/_jsx("p", {
...blockProps,
children: __('No results found.')
});
}
return /*#__PURE__*/_jsx(CommentsList, {
comments: commentTree,
blockProps: blockProps,
blocks: blocks,
activeCommentId: activeCommentId,
setActiveCommentId: setActiveCommentId,
firstCommentId: commentTree[0]?.commentId
});
}
//# sourceMappingURL=edit.js.map