@wordpress/editor 14.33.3-next.36001005c.0 → 14.33.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/build/bindings/post-data.js +49 -72
  2. package/build/bindings/post-data.js.map +3 -3
  3. package/build/bindings/post-meta.js +46 -47
  4. package/build/bindings/post-meta.js.map +2 -2
  5. package/build/bindings/term-data.js +6 -16
  6. package/build/bindings/term-data.js.map +2 -2
  7. package/build/components/block-settings-menu/content-only-settings-menu.js +186 -0
  8. package/build/components/block-settings-menu/content-only-settings-menu.js.map +7 -0
  9. package/build/components/collab-sidebar/add-comment.js +34 -7
  10. package/build/components/collab-sidebar/add-comment.js.map +3 -3
  11. package/build/components/collab-sidebar/comment-author-info.js +27 -15
  12. package/build/components/collab-sidebar/comment-author-info.js.map +2 -2
  13. package/build/components/collab-sidebar/comment-indicator-toolbar.js +15 -45
  14. package/build/components/collab-sidebar/comment-indicator-toolbar.js.map +3 -3
  15. package/build/components/collab-sidebar/comments.js +137 -35
  16. package/build/components/collab-sidebar/comments.js.map +3 -3
  17. package/build/components/collab-sidebar/hooks.js +8 -7
  18. package/build/components/collab-sidebar/hooks.js.map +2 -2
  19. package/build/components/collab-sidebar/index.js +56 -60
  20. package/build/components/collab-sidebar/index.js.map +3 -3
  21. package/build/components/editor/index.js +2 -0
  22. package/build/components/editor/index.js.map +3 -3
  23. package/build/components/header/index.js +0 -3
  24. package/build/components/header/index.js.map +3 -3
  25. package/build/components/more-menu/index.js +1 -1
  26. package/build/components/more-menu/index.js.map +2 -2
  27. package/build/components/post-template/hooks.js +7 -38
  28. package/build/components/post-template/hooks.js.map +2 -2
  29. package/build/components/provider/index.js +3 -1
  30. package/build/components/provider/index.js.map +3 -3
  31. package/build/components/visual-editor/index.js +20 -9
  32. package/build/components/visual-editor/index.js.map +2 -2
  33. package/build/store/actions.js +1 -1
  34. package/build/store/actions.js.map +2 -2
  35. package/build/store/private-actions.js +8 -0
  36. package/build/store/private-actions.js.map +2 -2
  37. package/build/store/private-selectors.js +5 -0
  38. package/build/store/private-selectors.js.map +2 -2
  39. package/build/store/reducer.js +10 -0
  40. package/build/store/reducer.js.map +2 -2
  41. package/build-module/bindings/post-data.js +49 -72
  42. package/build-module/bindings/post-data.js.map +2 -2
  43. package/build-module/bindings/post-meta.js +46 -47
  44. package/build-module/bindings/post-meta.js.map +2 -2
  45. package/build-module/bindings/term-data.js +6 -16
  46. package/build-module/bindings/term-data.js.map +2 -2
  47. package/build-module/components/block-settings-menu/content-only-settings-menu.js +161 -0
  48. package/build-module/components/block-settings-menu/content-only-settings-menu.js.map +7 -0
  49. package/build-module/components/collab-sidebar/add-comment.js +36 -9
  50. package/build-module/components/collab-sidebar/add-comment.js.map +2 -2
  51. package/build-module/components/collab-sidebar/comment-author-info.js +27 -15
  52. package/build-module/components/collab-sidebar/comment-author-info.js.map +2 -2
  53. package/build-module/components/collab-sidebar/comment-indicator-toolbar.js +21 -37
  54. package/build-module/components/collab-sidebar/comment-indicator-toolbar.js.map +2 -2
  55. package/build-module/components/collab-sidebar/comments.js +147 -38
  56. package/build-module/components/collab-sidebar/comments.js.map +2 -2
  57. package/build-module/components/collab-sidebar/hooks.js +8 -7
  58. package/build-module/components/collab-sidebar/hooks.js.map +2 -2
  59. package/build-module/components/collab-sidebar/index.js +56 -60
  60. package/build-module/components/collab-sidebar/index.js.map +2 -2
  61. package/build-module/components/editor/index.js +2 -0
  62. package/build-module/components/editor/index.js.map +2 -2
  63. package/build-module/components/header/index.js +0 -3
  64. package/build-module/components/header/index.js.map +2 -2
  65. package/build-module/components/more-menu/index.js +1 -1
  66. package/build-module/components/more-menu/index.js.map +2 -2
  67. package/build-module/components/post-template/hooks.js +7 -38
  68. package/build-module/components/post-template/hooks.js.map +2 -2
  69. package/build-module/components/provider/index.js +3 -1
  70. package/build-module/components/provider/index.js.map +2 -2
  71. package/build-module/components/visual-editor/index.js +20 -9
  72. package/build-module/components/visual-editor/index.js.map +2 -2
  73. package/build-module/store/actions.js +1 -1
  74. package/build-module/store/actions.js.map +2 -2
  75. package/build-module/store/private-actions.js +7 -0
  76. package/build-module/store/private-actions.js.map +2 -2
  77. package/build-module/store/private-selectors.js +4 -0
  78. package/build-module/store/private-selectors.js.map +2 -2
  79. package/build-module/store/reducer.js +9 -0
  80. package/build-module/store/reducer.js.map +2 -2
  81. package/build-style/style-rtl.css +18 -66
  82. package/build-style/style.css +18 -66
  83. package/build-types/bindings/post-data.d.ts +20 -20
  84. package/build-types/bindings/post-meta.d.ts +1 -14
  85. package/build-types/bindings/term-data.d.ts +6 -16
  86. package/build-types/components/block-settings-menu/content-only-settings-menu.d.ts +2 -0
  87. package/build-types/components/block-settings-menu/content-only-settings-menu.d.ts.map +1 -0
  88. package/build-types/components/collab-sidebar/add-comment.d.ts +6 -1
  89. package/build-types/components/collab-sidebar/add-comment.d.ts.map +1 -1
  90. package/build-types/components/collab-sidebar/comment-author-info.d.ts +5 -16
  91. package/build-types/components/collab-sidebar/comment-author-info.d.ts.map +1 -1
  92. package/build-types/components/collab-sidebar/comment-indicator-toolbar.d.ts +1 -2
  93. package/build-types/components/collab-sidebar/comment-indicator-toolbar.d.ts.map +1 -1
  94. package/build-types/components/collab-sidebar/comments.d.ts +12 -26
  95. package/build-types/components/collab-sidebar/comments.d.ts.map +1 -1
  96. package/build-types/components/collab-sidebar/hooks.d.ts +0 -1
  97. package/build-types/components/collab-sidebar/hooks.d.ts.map +1 -1
  98. package/build-types/components/collab-sidebar/index.d.ts +1 -4
  99. package/build-types/components/collab-sidebar/index.d.ts.map +1 -1
  100. package/build-types/components/editor/index.d.ts.map +1 -1
  101. package/build-types/components/header/index.d.ts.map +1 -1
  102. package/build-types/components/post-template/hooks.d.ts +1 -1
  103. package/build-types/components/post-template/hooks.d.ts.map +1 -1
  104. package/build-types/components/provider/index.d.ts.map +1 -1
  105. package/build-types/components/visual-editor/index.d.ts.map +1 -1
  106. package/build-types/store/actions.d.ts.map +1 -1
  107. package/build-types/store/private-actions.d.ts +7 -0
  108. package/build-types/store/private-actions.d.ts.map +1 -1
  109. package/build-types/store/private-selectors.d.ts +7 -0
  110. package/build-types/store/private-selectors.d.ts.map +1 -1
  111. package/build-types/store/reducer.d.ts +10 -0
  112. package/build-types/store/reducer.d.ts.map +1 -1
  113. package/package.json +38 -38
  114. package/src/bindings/post-data.js +65 -124
  115. package/src/bindings/post-meta.js +56 -58
  116. package/src/bindings/term-data.js +6 -21
  117. package/src/bindings/test/post-meta.js +211 -0
  118. package/src/components/block-settings-menu/content-only-settings-menu.js +185 -0
  119. package/src/components/block-settings-menu/content-only-settings-menu.native.js +4 -0
  120. package/src/components/block-settings-menu/style.scss +6 -0
  121. package/src/components/collab-sidebar/add-comment.js +41 -8
  122. package/src/components/collab-sidebar/comment-author-info.js +33 -26
  123. package/src/components/collab-sidebar/comment-indicator-toolbar.js +25 -51
  124. package/src/components/collab-sidebar/comments.js +147 -43
  125. package/src/components/collab-sidebar/hooks.js +9 -8
  126. package/src/components/collab-sidebar/index.js +58 -48
  127. package/src/components/collab-sidebar/style.scss +8 -69
  128. package/src/components/editor/index.js +2 -0
  129. package/src/components/editor-help/style.scss +1 -1
  130. package/src/components/header/index.js +0 -7
  131. package/src/components/more-menu/index.js +1 -1
  132. package/src/components/post-last-revision/style.scss +1 -1
  133. package/src/components/post-panel-row/style.scss +0 -1
  134. package/src/components/post-publish-panel/style.scss +1 -1
  135. package/src/components/post-publish-panel/test/__snapshots__/index.js.snap +2 -2
  136. package/src/components/post-template/hooks.js +10 -51
  137. package/src/components/provider/index.js +3 -4
  138. package/src/components/visual-editor/index.js +27 -6
  139. package/src/store/actions.js +4 -1
  140. package/src/store/private-actions.js +13 -0
  141. package/src/store/private-selectors.js +10 -0
  142. package/src/store/reducer.js +16 -0
  143. package/src/style.scss +1 -0
  144. package/tsconfig.tsbuildinfo +1 -1
@@ -1,16 +1,15 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { ToolbarButton } from '@wordpress/components';
5
- import { __, _n, sprintf } from '@wordpress/i18n';
4
+ import {
5
+ ToolbarButton,
6
+ __experimentalText as Text,
7
+ __experimentalHStack as HStack,
8
+ } from '@wordpress/components';
9
+ import { __, sprintf } from '@wordpress/i18n';
6
10
  import { useMemo } from '@wordpress/element';
7
11
  import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor';
8
12
 
9
- /**
10
- * External dependencies
11
- */
12
- import clsx from 'clsx';
13
-
14
13
  /**
15
14
  * Internal dependencies
16
15
  */
@@ -19,7 +18,7 @@ import { getAvatarBorderColor } from './utils';
19
18
 
20
19
  const { CommentIconToolbarSlotFill } = unlock( blockEditorPrivateApis );
21
20
 
22
- const CommentAvatarIndicator = ( { onClick, thread, hasMoreComments } ) => {
21
+ const CommentAvatarIndicator = ( { onClick, thread } ) => {
23
22
  const threadParticipants = useMemo( () => {
24
23
  if ( ! thread ) {
25
24
  return [];
@@ -34,15 +33,13 @@ const CommentAvatarIndicator = ( { onClick, thread, hasMoreComments } ) => {
34
33
  allComments.forEach( ( comment ) => {
35
34
  // Track thread participants (original commenter + repliers).
36
35
  if ( comment.author_name && comment.author_avatar_urls ) {
37
- const authorKey = `${ comment.author }-${ comment.author_name }`;
38
- if ( ! participantsMap.has( authorKey ) ) {
39
- participantsMap.set( authorKey, {
36
+ if ( ! participantsMap.has( comment.author ) ) {
37
+ participantsMap.set( comment.author, {
40
38
  name: comment.author_name,
41
39
  avatar:
42
40
  comment.author_avatar_urls?.[ '48' ] ||
43
41
  comment.author_avatar_urls?.[ '96' ],
44
42
  id: comment.author,
45
- isOriginalCommenter: comment.id === thread.id,
46
43
  date: comment.date,
47
44
  } );
48
45
  }
@@ -52,22 +49,21 @@ const CommentAvatarIndicator = ( { onClick, thread, hasMoreComments } ) => {
52
49
  return Array.from( participantsMap.values() );
53
50
  }, [ thread ] );
54
51
 
55
- const hasUnresolved = thread?.status !== 'approved';
56
-
57
- // Check if this specific thread has more participants due to pagination.
58
- // If we have pagination AND this thread + its replies equals or exceeds the API limit,
59
- // then this thread likely has more participants that weren't loaded.
60
- const threadHasMoreParticipants =
61
- hasMoreComments && thread?.reply && 1 + thread.reply.length >= 100;
62
-
63
52
  if ( ! threadParticipants.length ) {
64
53
  return null;
65
54
  }
66
55
 
67
- // Show up to 3 avatars, with overflow indicator.
56
+ // If there are more than 3 participants, show 2 avatars and a "+n" number.
68
57
  const maxAvatars = 3;
69
- const visibleParticipants = threadParticipants.slice( 0, maxAvatars );
70
- const overflowCount = Math.max( 0, threadParticipants.length - maxAvatars );
58
+ const isOverflow = threadParticipants.length > maxAvatars;
59
+ const visibleParticipants = isOverflow
60
+ ? threadParticipants.slice( 0, maxAvatars - 1 )
61
+ : threadParticipants;
62
+ const overflowCount = Math.max(
63
+ 0,
64
+ threadParticipants.length - visibleParticipants.length
65
+ );
66
+ const threadHasMoreParticipants = threadParticipants.length > 100;
71
67
 
72
68
  // If we hit the comment limit, show "100+" instead of exact overflow count.
73
69
  const overflowText =
@@ -79,38 +75,22 @@ const CommentAvatarIndicator = ( { onClick, thread, hasMoreComments } ) => {
79
75
  overflowCount
80
76
  );
81
77
 
82
- const overflowTitle =
83
- threadHasMoreParticipants && overflowCount > 0
84
- ? __( '100+ participants' )
85
- : sprintf(
86
- // translators: %s: Number of participants.
87
- _n(
88
- '+%s more participant',
89
- '+%s more participants',
90
- overflowCount
91
- ),
92
- overflowCount
93
- );
94
-
95
78
  return (
96
79
  <CommentIconToolbarSlotFill.Fill>
97
80
  <ToolbarButton
98
- className={ clsx( 'comment-avatar-indicator', {
99
- 'has-unresolved': hasUnresolved,
100
- } ) }
81
+ className="comment-avatar-indicator"
101
82
  label={ __( 'View notes' ) }
102
83
  onClick={ onClick }
103
84
  showTooltip
104
85
  >
105
- <div className="comment-avatar-stack">
106
- { visibleParticipants.map( ( participant, index ) => (
86
+ <HStack spacing="1">
87
+ { visibleParticipants.map( ( participant ) => (
107
88
  <img
108
- key={ participant.name + index }
89
+ key={ participant.id }
109
90
  src={ participant.avatar }
110
91
  alt={ participant.name }
111
92
  className="comment-avatar"
112
93
  style={ {
113
- zIndex: maxAvatars - index,
114
94
  borderColor: getAvatarBorderColor(
115
95
  participant.id
116
96
  ),
@@ -118,15 +98,9 @@ const CommentAvatarIndicator = ( { onClick, thread, hasMoreComments } ) => {
118
98
  />
119
99
  ) ) }
120
100
  { overflowCount > 0 && (
121
- <div
122
- className="comment-avatar-overflow"
123
- style={ { zIndex: 0 } }
124
- title={ overflowTitle }
125
- >
126
- { overflowText }
127
- </div>
101
+ <Text weight={ 500 }>{ overflowText }</Text>
128
102
  ) }
129
- </div>
103
+ </HStack>
130
104
  </ToolbarButton>
131
105
  </CommentIconToolbarSlotFill.Fill>
132
106
  );
@@ -6,7 +6,14 @@ import clsx from 'clsx';
6
6
  /**
7
7
  * WordPress dependencies
8
8
  */
9
- import { useState, RawHTML, useEffect, useCallback } from '@wordpress/element';
9
+ import {
10
+ useState,
11
+ RawHTML,
12
+ useEffect,
13
+ useCallback,
14
+ useMemo,
15
+ useRef,
16
+ } from '@wordpress/element';
10
17
  import {
11
18
  __experimentalText as Text,
12
19
  __experimentalHStack as HStack,
@@ -33,32 +40,20 @@ import {
33
40
  import { unlock } from '../../lock-unlock';
34
41
  import CommentAuthorInfo from './comment-author-info';
35
42
  import CommentForm from './comment-form';
36
- import { getCommentExcerpt, focusCommentThread } from './utils';
43
+ import { focusCommentThread, getCommentExcerpt } from './utils';
37
44
  import { useFloatingThread } from './hooks';
45
+ import { AddComment } from './add-comment';
46
+ import { store as editorStore } from '../../store';
38
47
 
39
48
  const { useBlockElement } = unlock( blockEditorPrivateApis );
40
49
  const { Menu } = unlock( componentsPrivateApis );
41
50
 
42
- /**
43
- * Renders the Comments component.
44
- *
45
- * @param {Object} props - The component props.
46
- * @param {Array} props.threads - The array of comment threads.
47
- * @param {Function} props.onEditComment - The function to handle comment editing.
48
- * @param {Function} props.onAddReply - The function to add a reply to a comment.
49
- * @param {Function} props.onCommentDelete - The function to delete a comment.
50
- * @param {Function} props.setShowCommentBoard - The function to set the comment board visibility.
51
- * @param {Ref} props.commentSidebarRef - The ref to the comment sidebar.
52
- * @param {Function} props.reflowComments - The function to call indicating a comment is updated.
53
- * @param {boolean} props.isFloating - Whether the comment thread is floating.
54
- * @param {number} props.commentLastUpdated - Timestamp of the last comment update.
55
- * @return {React.ReactNode} The rendered Comments component.
56
- */
57
51
  export function Comments( {
58
- threads,
52
+ threads: noteThreads,
59
53
  onEditComment,
60
54
  onAddReply,
61
55
  onCommentDelete,
56
+ showCommentBoard,
62
57
  setShowCommentBoard,
63
58
  commentSidebarRef,
64
59
  reflowComments,
@@ -70,20 +65,63 @@ export function Comments( {
70
65
  const [ boardOffsets, setBoardOffsets ] = useState( {} );
71
66
  const [ blockRefs, setBlockRefs ] = useState( {} );
72
67
 
73
- const { blockCommentId, selectedBlockClientId } = useSelect( ( select ) => {
74
- const { getBlockAttributes, getSelectedBlockClientId } =
75
- select( blockEditorStore );
76
- const clientId = getSelectedBlockClientId();
77
- return {
78
- blockCommentId: clientId
79
- ? getBlockAttributes( clientId )?.metadata?.noteId
80
- : null,
81
- selectedBlockClientId: clientId,
82
- };
83
- }, [] );
68
+ const { setCanvasMinHeight } = unlock( useDispatch( editorStore ) );
69
+ const { blockCommentId, selectedBlockClientId, orderedBlockIds } =
70
+ useSelect( ( select ) => {
71
+ const { getBlockAttributes, getSelectedBlockClientId } =
72
+ select( blockEditorStore );
73
+ const clientId = getSelectedBlockClientId();
74
+ return {
75
+ blockCommentId: clientId
76
+ ? getBlockAttributes( clientId )?.metadata?.noteId
77
+ : null,
78
+ selectedBlockClientId: clientId,
79
+ orderedBlockIds: select( blockEditorStore ).getBlockOrder(),
80
+ };
81
+ }, [] );
84
82
 
85
83
  const relatedBlockElement = useBlockElement( selectedBlockClientId );
86
84
 
85
+ const threads = useMemo( () => {
86
+ const t = [ ...noteThreads ];
87
+ const orderedThreads = [];
88
+ // In floating mode, when the note board is shown, and as long
89
+ // as the selected block doesn't have an existing note attached -
90
+ // add a "new note" entry to the threads. This special thread type
91
+ // gets sorted and floated like regular threads, but shows an AddComment
92
+ // component instead of a regular comment thread.
93
+ if ( isFloating && showCommentBoard && undefined === blockCommentId ) {
94
+ // Insert the new note entry at the correct location for its blockId.
95
+ const newNoteThread = {
96
+ id: 'new-note-thread',
97
+ blockClientId: selectedBlockClientId,
98
+ content: { rendered: '' },
99
+ };
100
+ // Insert the new comment block at the right order within the threads.
101
+ orderedBlockIds.forEach( ( blockId ) => {
102
+ if ( blockId === selectedBlockClientId ) {
103
+ orderedThreads.push( newNoteThread );
104
+ } else {
105
+ const threadForBlock = t.find(
106
+ ( thread ) => thread.blockClientId === blockId
107
+ );
108
+ if ( threadForBlock ) {
109
+ orderedThreads.push( threadForBlock );
110
+ }
111
+ }
112
+ } );
113
+ return orderedThreads;
114
+ }
115
+ return t;
116
+ }, [
117
+ noteThreads,
118
+ isFloating,
119
+ showCommentBoard,
120
+ blockCommentId,
121
+ selectedBlockClientId,
122
+ orderedBlockIds,
123
+ ] );
124
+
87
125
  const handleDelete = async ( comment ) => {
88
126
  const currentIndex = threads.findIndex( ( t ) => t.id === comment.id );
89
127
  const nextThread = threads[ currentIndex + 1 ];
@@ -114,8 +152,10 @@ export function Comments( {
114
152
 
115
153
  // Auto-select the related comment thread when a block is selected.
116
154
  useEffect( () => {
117
- setSelectedThread( blockCommentId ?? undefined );
118
- }, [ blockCommentId ] );
155
+ // Fallback to 'new-note-thread' when showing the comment board for a new note.
156
+ const fallback = showCommentBoard ? 'new-note-thread' : null;
157
+ setSelectedThread( blockCommentId ?? fallback );
158
+ }, [ blockCommentId, showCommentBoard ] );
119
159
 
120
160
  const setBlockRef = useCallback( ( id, blockRef ) => {
121
161
  setBlockRefs( ( prev ) => ( { ...prev, [ id ]: blockRef } ) );
@@ -131,7 +171,7 @@ export function Comments( {
131
171
  const offsets = {};
132
172
 
133
173
  if ( ! isFloating ) {
134
- return offsets;
174
+ return { offsets, minHeight: 0 };
135
175
  }
136
176
 
137
177
  // Find the index of the selected thread.
@@ -149,7 +189,7 @@ export function Comments( {
149
189
  ! selectedThreadData ||
150
190
  ! blockRefs[ selectedThreadData.id ]
151
191
  ) {
152
- return offsets;
192
+ return { offsets, minHeight: 0 };
153
193
  }
154
194
 
155
195
  let blockElement = blockRefs[ selectedThreadData.id ];
@@ -236,28 +276,67 @@ export function Comments( {
236
276
  threadTop: threadTop + additionalOffset,
237
277
  };
238
278
  }
239
- return offsets;
279
+
280
+ let editorMinHeight = 0;
281
+ // Take the calculated top of the final note plus its height as the editor min height.
282
+ const lastThread = threads[ threads.length - 1 ];
283
+ if ( blockRefs[ lastThread.id ] ) {
284
+ const lastBlockElement = blockRefs[ lastThread.id ];
285
+ const lastBlockRect = lastBlockElement?.getBoundingClientRect();
286
+ const lastThreadTop = lastBlockRect?.top || 0;
287
+ const lastThreadHeight = heights[ lastThread.id ] || 0;
288
+ const lastThreadOffset = offsets[ lastThread.id ] || 0;
289
+ editorMinHeight =
290
+ lastThreadTop + lastThreadHeight + lastThreadOffset + 32;
291
+ }
292
+
293
+ return { offsets, minHeight: editorMinHeight };
240
294
  };
241
- const newOffsets = calculateAllOffsets();
295
+ const { offsets: newOffsets, minHeight } = calculateAllOffsets();
242
296
  if ( Object.keys( newOffsets ).length > 0 ) {
243
297
  setBoardOffsets( newOffsets );
244
298
  }
245
- }, [ heights, blockRefs, isFloating, threads, selectedThread ] );
299
+ // Ensure the editor has enough height to scroll to all notes.
300
+ setCanvasMinHeight( minHeight );
301
+ }, [
302
+ heights,
303
+ blockRefs,
304
+ isFloating,
305
+ threads,
306
+ selectedThread,
307
+ setCanvasMinHeight,
308
+ ] );
246
309
 
247
310
  const hasThreads = Array.isArray( threads ) && threads.length > 0;
248
311
  if ( ! hasThreads && ! isFloating ) {
249
312
  return (
250
- <VStack alignment="left" justify="flex-start" spacing="2">
313
+ <>
314
+ <AddComment
315
+ onSubmit={ onAddReply }
316
+ showCommentBoard={ showCommentBoard }
317
+ setShowCommentBoard={ setShowCommentBoard }
318
+ commentSidebarRef={ commentSidebarRef }
319
+ />
251
320
  <Text as="p">{ __( 'No notes available.' ) }</Text>
252
321
  <Text as="p" variant="muted">
253
322
  { __( 'Only logged in users can see Notes.' ) }
254
323
  </Text>
255
- </VStack>
324
+ </>
256
325
  );
257
326
  }
258
327
 
259
328
  return (
260
- <VStack spacing="3">
329
+ <>
330
+ { ! isFloating &&
331
+ showCommentBoard &&
332
+ undefined === blockCommentId && (
333
+ <AddComment
334
+ onSubmit={ onAddReply }
335
+ showCommentBoard={ showCommentBoard }
336
+ setShowCommentBoard={ setShowCommentBoard }
337
+ commentSidebarRef={ commentSidebarRef }
338
+ />
339
+ ) }
261
340
  { threads.map( ( thread ) => (
262
341
  <Thread
263
342
  key={ thread.id }
@@ -276,9 +355,10 @@ export function Comments( {
276
355
  setBlockRef={ setBlockRef }
277
356
  selectedThread={ selectedThread }
278
357
  commentLastUpdated={ commentLastUpdated }
358
+ showCommentBoard={ showCommentBoard }
279
359
  />
280
360
  ) ) }
281
- </VStack>
361
+ </>
282
362
  );
283
363
  }
284
364
 
@@ -298,6 +378,7 @@ function Thread( {
298
378
  setSelectedThread,
299
379
  selectedThread,
300
380
  commentLastUpdated,
381
+ showCommentBoard,
301
382
  } ) {
302
383
  const { toggleBlockHighlight, selectBlock, toggleBlockSpotlight } = unlock(
303
384
  useDispatch( blockEditorStore )
@@ -347,7 +428,7 @@ function Thread( {
347
428
  const restReplies = allReplies.length > 0 ? allReplies.slice( 0, -1 ) : [];
348
429
 
349
430
  const commentExcerpt = getCommentExcerpt(
350
- stripHTML( thread.content.rendered ),
431
+ stripHTML( thread.content?.rendered ),
351
432
  10
352
433
  );
353
434
  const ariaLabel = !! thread.blockClientId
@@ -362,6 +443,21 @@ function Thread( {
362
443
  commentExcerpt
363
444
  );
364
445
 
446
+ if ( 'new-note-thread' === thread.id && showCommentBoard && isFloating ) {
447
+ return (
448
+ <AddComment
449
+ onSubmit={ onAddReply }
450
+ showCommentBoard={ showCommentBoard }
451
+ setShowCommentBoard={ setShowCommentBoard }
452
+ commentSidebarRef={ commentSidebarRef }
453
+ reflowComments={ reflowComments }
454
+ isFloating={ isFloating }
455
+ y={ y }
456
+ refs={ refs }
457
+ />
458
+ );
459
+ }
460
+
365
461
  return (
366
462
  // Disable reason: role="listitem" does in fact support aria-expanded.
367
463
  // eslint-disable-next-line jsx-a11y/role-supports-aria-props
@@ -378,6 +474,9 @@ function Thread( {
378
474
  onFocus={ onMouseEnter }
379
475
  onBlur={ onMouseLeave }
380
476
  onKeyDown={ ( event ) => {
477
+ if ( event.defaultPrevented ) {
478
+ return;
479
+ }
381
480
  // Expand or Collapse thread.
382
481
  if (
383
482
  event.key === 'Enter' &&
@@ -562,7 +661,7 @@ const CommentBoard = ( {
562
661
  } ) => {
563
662
  const [ actionState, setActionState ] = useState( false );
564
663
  const [ showConfirmDialog, setShowConfirmDialog ] = useState( false );
565
-
664
+ const actionButtonRef = useRef( null );
566
665
  const handleConfirmDelete = () => {
567
666
  onDelete( thread );
568
667
  setActionState( false );
@@ -572,6 +671,7 @@ const CommentBoard = ( {
572
671
  const handleCancel = () => {
573
672
  setActionState( false );
574
673
  setShowConfirmDialog( false );
674
+ actionButtonRef.current?.focus();
575
675
  };
576
676
 
577
677
  // Check if this is a resolution comment by checking metadata.
@@ -657,6 +757,7 @@ const CommentBoard = ( {
657
757
  <Menu.TriggerButton
658
758
  render={
659
759
  <Button
760
+ ref={ actionButtonRef }
660
761
  size="small"
661
762
  icon={ moreVertical }
662
763
  label={ __( 'Actions' ) }
@@ -690,6 +791,7 @@ const CommentBoard = ( {
690
791
  content: value,
691
792
  } );
692
793
  setActionState( false );
794
+ actionButtonRef.current?.focus();
693
795
  } }
694
796
  onCancel={ () => handleCancel() }
695
797
  thread={ thread }
@@ -745,7 +847,9 @@ const CommentBoard = ( {
745
847
  onCancel={ handleCancel }
746
848
  confirmButtonText={ __( 'Delete' ) }
747
849
  >
748
- { __( 'Are you sure you want to delete this note?' ) }
850
+ { __(
851
+ "Are you sure you want to delete this note? This will also delete all of this note's replies."
852
+ ) }
749
853
  </ConfirmDialog>
750
854
  ) }
751
855
  </VStack>
@@ -50,10 +50,10 @@ export function useBlockComments( postId ) {
50
50
  post: postId,
51
51
  type: 'note',
52
52
  status: 'all',
53
- per_page: 100,
53
+ per_page: -1,
54
54
  };
55
55
 
56
- const { records: threads, totalPages } = useEntityRecords(
56
+ const { records: threads } = useEntityRecords(
57
57
  'root',
58
58
  'comment',
59
59
  queryArgs,
@@ -70,6 +70,10 @@ export function useBlockComments( postId ) {
70
70
 
71
71
  // Process comments to build the tree structure.
72
72
  const { resultComments, unresolvedSortedThreads } = useMemo( () => {
73
+ if ( ! threads || threads.length === 0 ) {
74
+ return { resultComments: [], unresolvedSortedThreads: [] };
75
+ }
76
+
73
77
  const blocksWithComments = clientIds.reduce( ( results, clientId ) => {
74
78
  const commentId = getBlockAttributes( clientId )?.metadata?.noteId;
75
79
  if ( commentId ) {
@@ -82,10 +86,8 @@ export function useBlockComments( postId ) {
82
86
  const compare = {};
83
87
  const result = [];
84
88
 
85
- const allComments = threads ?? [];
86
-
87
89
  // Initialize each object with an empty `reply` array and map blockClientId.
88
- allComments.forEach( ( item ) => {
90
+ threads.forEach( ( item ) => {
89
91
  const itemBlock = Object.keys( blocksWithComments ).find(
90
92
  ( key ) => blocksWithComments[ key ] === item.id
91
93
  );
@@ -98,7 +100,7 @@ export function useBlockComments( postId ) {
98
100
  } );
99
101
 
100
102
  // Iterate over the data to build the tree structure.
101
- allComments.forEach( ( item ) => {
103
+ threads.forEach( ( item ) => {
102
104
  if ( item.parent === 0 ) {
103
105
  // If parent is 0, it's a root item, push it to the result array.
104
106
  result.push( compare[ item.id ] );
@@ -160,7 +162,6 @@ export function useBlockComments( postId ) {
160
162
  return {
161
163
  resultComments,
162
164
  unresolvedSortedThreads,
163
- totalPages,
164
165
  reflowComments,
165
166
  commentLastUpdated,
166
167
  };
@@ -399,7 +400,7 @@ export function useFloatingThread( {
399
400
  if ( blockRef.current ) {
400
401
  refs.setReference( blockRef.current );
401
402
  }
402
- }, [ blockRef, refs ] );
403
+ }, [ blockRef, refs, commentLastUpdated ] );
403
404
 
404
405
  // Track thread heights.
405
406
  useEffect( () => {