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

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 (104) hide show
  1. package/build/bindings/post-data.js +10 -17
  2. package/build/bindings/post-data.js.map +2 -2
  3. package/build/bindings/post-meta.js +7 -14
  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 +26 -3
  10. package/build/components/collab-sidebar/add-comment.js.map +3 -3
  11. package/build/components/collab-sidebar/comment-indicator-toolbar.js +6 -22
  12. package/build/components/collab-sidebar/comment-indicator-toolbar.js.map +3 -3
  13. package/build/components/collab-sidebar/comments.js +105 -28
  14. package/build/components/collab-sidebar/comments.js.map +3 -3
  15. package/build/components/collab-sidebar/hooks.js +3 -4
  16. package/build/components/collab-sidebar/hooks.js.map +2 -2
  17. package/build/components/collab-sidebar/index.js +42 -57
  18. package/build/components/collab-sidebar/index.js.map +3 -3
  19. package/build/components/editor/index.js +2 -0
  20. package/build/components/editor/index.js.map +3 -3
  21. package/build/components/header/index.js +0 -3
  22. package/build/components/header/index.js.map +3 -3
  23. package/build/components/post-template/hooks.js +7 -38
  24. package/build/components/post-template/hooks.js.map +2 -2
  25. package/build/components/provider/index.js +3 -1
  26. package/build/components/provider/index.js.map +3 -3
  27. package/build/store/actions.js +1 -1
  28. package/build/store/actions.js.map +2 -2
  29. package/build-module/bindings/post-data.js +10 -17
  30. package/build-module/bindings/post-data.js.map +2 -2
  31. package/build-module/bindings/post-meta.js +7 -14
  32. package/build-module/bindings/post-meta.js.map +2 -2
  33. package/build-module/bindings/term-data.js +6 -16
  34. package/build-module/bindings/term-data.js.map +2 -2
  35. package/build-module/components/block-settings-menu/content-only-settings-menu.js +161 -0
  36. package/build-module/components/block-settings-menu/content-only-settings-menu.js.map +7 -0
  37. package/build-module/components/collab-sidebar/add-comment.js +27 -4
  38. package/build-module/components/collab-sidebar/add-comment.js.map +2 -2
  39. package/build-module/components/collab-sidebar/comment-indicator-toolbar.js +6 -12
  40. package/build-module/components/collab-sidebar/comment-indicator-toolbar.js.map +2 -2
  41. package/build-module/components/collab-sidebar/comments.js +114 -31
  42. package/build-module/components/collab-sidebar/comments.js.map +2 -2
  43. package/build-module/components/collab-sidebar/hooks.js +3 -4
  44. package/build-module/components/collab-sidebar/hooks.js.map +2 -2
  45. package/build-module/components/collab-sidebar/index.js +42 -57
  46. package/build-module/components/collab-sidebar/index.js.map +2 -2
  47. package/build-module/components/editor/index.js +2 -0
  48. package/build-module/components/editor/index.js.map +2 -2
  49. package/build-module/components/header/index.js +0 -3
  50. package/build-module/components/header/index.js.map +2 -2
  51. package/build-module/components/post-template/hooks.js +7 -38
  52. package/build-module/components/post-template/hooks.js.map +2 -2
  53. package/build-module/components/provider/index.js +3 -1
  54. package/build-module/components/provider/index.js.map +2 -2
  55. package/build-module/store/actions.js +1 -1
  56. package/build-module/store/actions.js.map +2 -2
  57. package/build-style/style-rtl.css +12 -23
  58. package/build-style/style.css +12 -23
  59. package/build-types/bindings/post-data.d.ts +6 -16
  60. package/build-types/bindings/post-meta.d.ts +6 -13
  61. package/build-types/bindings/term-data.d.ts +6 -16
  62. package/build-types/components/block-settings-menu/content-only-settings-menu.d.ts +2 -0
  63. package/build-types/components/block-settings-menu/content-only-settings-menu.d.ts.map +1 -0
  64. package/build-types/components/collab-sidebar/add-comment.d.ts +6 -1
  65. package/build-types/components/collab-sidebar/add-comment.d.ts.map +1 -1
  66. package/build-types/components/collab-sidebar/comment-indicator-toolbar.d.ts +1 -2
  67. package/build-types/components/collab-sidebar/comment-indicator-toolbar.d.ts.map +1 -1
  68. package/build-types/components/collab-sidebar/comments.d.ts +12 -26
  69. package/build-types/components/collab-sidebar/comments.d.ts.map +1 -1
  70. package/build-types/components/collab-sidebar/hooks.d.ts +0 -1
  71. package/build-types/components/collab-sidebar/hooks.d.ts.map +1 -1
  72. package/build-types/components/collab-sidebar/index.d.ts +1 -4
  73. package/build-types/components/collab-sidebar/index.d.ts.map +1 -1
  74. package/build-types/components/editor/index.d.ts.map +1 -1
  75. package/build-types/components/header/index.d.ts.map +1 -1
  76. package/build-types/components/post-template/hooks.d.ts +1 -1
  77. package/build-types/components/post-template/hooks.d.ts.map +1 -1
  78. package/build-types/components/provider/index.d.ts.map +1 -1
  79. package/build-types/store/actions.d.ts.map +1 -1
  80. package/package.json +38 -38
  81. package/src/bindings/post-data.js +9 -20
  82. package/src/bindings/post-meta.js +6 -17
  83. package/src/bindings/term-data.js +6 -21
  84. package/src/components/block-settings-menu/content-only-settings-menu.js +185 -0
  85. package/src/components/block-settings-menu/content-only-settings-menu.native.js +4 -0
  86. package/src/components/block-settings-menu/style.scss +6 -0
  87. package/src/components/collab-sidebar/add-comment.js +31 -3
  88. package/src/components/collab-sidebar/comment-indicator-toolbar.js +6 -22
  89. package/src/components/collab-sidebar/comments.js +108 -35
  90. package/src/components/collab-sidebar/hooks.js +3 -4
  91. package/src/components/collab-sidebar/index.js +34 -42
  92. package/src/components/collab-sidebar/style.scss +2 -23
  93. package/src/components/editor/index.js +2 -0
  94. package/src/components/editor-help/style.scss +1 -1
  95. package/src/components/header/index.js +0 -7
  96. package/src/components/post-last-revision/style.scss +1 -1
  97. package/src/components/post-panel-row/style.scss +0 -1
  98. package/src/components/post-publish-panel/style.scss +1 -1
  99. package/src/components/post-publish-panel/test/__snapshots__/index.js.snap +2 -2
  100. package/src/components/post-template/hooks.js +10 -51
  101. package/src/components/provider/index.js +3 -4
  102. package/src/store/actions.js +4 -1
  103. package/src/style.scss +1 -0
  104. package/tsconfig.tsbuildinfo +1 -1
@@ -195,30 +195,15 @@ export default {
195
195
  return false;
196
196
  },
197
197
  getFieldsList( { select, context } ) {
198
- // Deprecated, will be removed after 6.9.
199
- return getTermDataFields( select, context );
200
- },
201
- editorUI( { select, context } ) {
202
- const selectedBlock = select( blockEditorStore ).getSelectedBlock();
203
- // Exit early for navigation blocks (read-only)
204
- if ( NAVIGATION_BLOCK_TYPES.includes( selectedBlock?.name ) ) {
205
- return {};
198
+ const clientId = select( blockEditorStore ).getSelectedBlockClientId();
199
+ const termDataFields = getTermDataFields( select, context, clientId );
200
+ if ( ! termDataFields ) {
201
+ return [];
206
202
  }
207
- const termDataFields = Object.entries(
208
- getTermDataFields( select, context ) || {}
209
- ).map( ( [ key, field ] ) => ( {
203
+ return Object.entries( termDataFields ).map( ( [ key, field ] ) => ( {
210
204
  label: field.label,
211
205
  type: field.type,
212
- args: {
213
- field: key,
214
- },
206
+ args: { field: key },
215
207
  } ) );
216
- /*
217
- * We need to define the data as [{ label: string, value: any, type: https://developer.wordpress.org/block-editor/reference-guides/block-api/block-attributes/#type-validation }]
218
- */
219
- return {
220
- mode: 'dropdown',
221
- data: termDataFields,
222
- };
223
208
  },
224
209
  };
@@ -0,0 +1,185 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import {
5
+ BlockSettingsMenuControls,
6
+ __unstableBlockSettingsMenuFirstItem as BlockSettingsMenuFirstItem,
7
+ store as blockEditorStore,
8
+ useBlockDisplayInformation,
9
+ } from '@wordpress/block-editor';
10
+ import { store as coreStore } from '@wordpress/core-data';
11
+ import { __experimentalText as Text, MenuItem } from '@wordpress/components';
12
+ import { useSelect, useDispatch } from '@wordpress/data';
13
+ import { __, _x } from '@wordpress/i18n';
14
+
15
+ /**
16
+ * Internal dependencies
17
+ */
18
+ import { store as editorStore } from '../../store';
19
+ import { unlock } from '../../lock-unlock';
20
+ import usePostContentBlocks from '../provider/use-post-content-blocks';
21
+
22
+ function ContentOnlySettingsMenuItems( { clientId, onClose } ) {
23
+ const postContentBlocks = usePostContentBlocks();
24
+ const { entity, onNavigateToEntityRecord, canEditTemplates } = useSelect(
25
+ ( select ) => {
26
+ const {
27
+ getBlockParentsByBlockName,
28
+ getSettings,
29
+ getBlockAttributes,
30
+ getBlockParents,
31
+ } = select( blockEditorStore );
32
+ const { getCurrentTemplateId, getRenderingMode } =
33
+ select( editorStore );
34
+ const patternParent = getBlockParentsByBlockName(
35
+ clientId,
36
+ 'core/block',
37
+ true
38
+ )[ 0 ];
39
+
40
+ let record;
41
+ if ( patternParent ) {
42
+ record = select( coreStore ).getEntityRecord(
43
+ 'postType',
44
+ 'wp_block',
45
+ getBlockAttributes( patternParent ).ref
46
+ );
47
+ } else if (
48
+ getRenderingMode() === 'template-locked' &&
49
+ ! getBlockParents( clientId ).some( ( parent ) =>
50
+ postContentBlocks.includes( parent )
51
+ )
52
+ ) {
53
+ record = select( coreStore ).getEntityRecord(
54
+ 'postType',
55
+ 'wp_template',
56
+ getCurrentTemplateId()
57
+ );
58
+ }
59
+ if ( ! record ) {
60
+ return {};
61
+ }
62
+ const _canEditTemplates = select( coreStore ).canUser( 'create', {
63
+ kind: 'postType',
64
+ name: 'wp_template',
65
+ } );
66
+ return {
67
+ canEditTemplates: _canEditTemplates,
68
+ entity: record,
69
+ onNavigateToEntityRecord:
70
+ getSettings().onNavigateToEntityRecord,
71
+ };
72
+ },
73
+ [ clientId, postContentBlocks ]
74
+ );
75
+
76
+ if ( ! entity ) {
77
+ return (
78
+ <TemplateLockContentOnlyMenuItems
79
+ clientId={ clientId }
80
+ onClose={ onClose }
81
+ />
82
+ );
83
+ }
84
+
85
+ const isPattern = entity.type === 'wp_block';
86
+ let helpText = isPattern
87
+ ? __(
88
+ 'Edit the pattern to move, delete, or make further changes to this block.'
89
+ )
90
+ : __(
91
+ 'Edit the template to move, delete, or make further changes to this block.'
92
+ );
93
+
94
+ if ( ! canEditTemplates ) {
95
+ helpText = __(
96
+ 'Only users with permissions to edit the template can move or delete this block'
97
+ );
98
+ }
99
+
100
+ return (
101
+ <>
102
+ <BlockSettingsMenuFirstItem>
103
+ <MenuItem
104
+ onClick={ () => {
105
+ onNavigateToEntityRecord( {
106
+ postId: entity.id,
107
+ postType: entity.type,
108
+ } );
109
+ } }
110
+ disabled={ ! canEditTemplates }
111
+ >
112
+ { isPattern ? __( 'Edit pattern' ) : __( 'Edit template' ) }
113
+ </MenuItem>
114
+ </BlockSettingsMenuFirstItem>
115
+ <Text
116
+ variant="muted"
117
+ as="p"
118
+ className="editor-content-only-settings-menu__description"
119
+ >
120
+ { helpText }
121
+ </Text>
122
+ </>
123
+ );
124
+ }
125
+
126
+ function TemplateLockContentOnlyMenuItems( { clientId, onClose } ) {
127
+ const { contentLockingParent } = useSelect(
128
+ ( select ) => {
129
+ const { getContentLockingParent } = unlock(
130
+ select( blockEditorStore )
131
+ );
132
+ return {
133
+ contentLockingParent: getContentLockingParent( clientId ),
134
+ };
135
+ },
136
+ [ clientId ]
137
+ );
138
+ const blockDisplayInformation =
139
+ useBlockDisplayInformation( contentLockingParent );
140
+ const blockEditorActions = useDispatch( blockEditorStore );
141
+ if ( ! blockDisplayInformation?.title ) {
142
+ return null;
143
+ }
144
+
145
+ const { modifyContentLockBlock } = unlock( blockEditorActions );
146
+
147
+ return (
148
+ <>
149
+ <BlockSettingsMenuFirstItem>
150
+ <MenuItem
151
+ onClick={ () => {
152
+ modifyContentLockBlock( contentLockingParent );
153
+ onClose();
154
+ } }
155
+ >
156
+ { _x( 'Unlock', 'Unlock content locked blocks' ) }
157
+ </MenuItem>
158
+ </BlockSettingsMenuFirstItem>
159
+ <Text
160
+ variant="muted"
161
+ as="p"
162
+ className="editor-content-only-settings-menu__description"
163
+ >
164
+ { __(
165
+ 'Temporarily unlock the parent block to edit, delete or make further changes to this block.'
166
+ ) }
167
+ </Text>
168
+ </>
169
+ );
170
+ }
171
+
172
+ export default function ContentOnlySettingsMenu() {
173
+ return (
174
+ <BlockSettingsMenuControls>
175
+ { ( { selectedClientIds, onClose } ) =>
176
+ selectedClientIds.length === 1 && (
177
+ <ContentOnlySettingsMenuItems
178
+ clientId={ selectedClientIds[ 0 ] }
179
+ onClose={ onClose }
180
+ />
181
+ )
182
+ }
183
+ </BlockSettingsMenuControls>
184
+ );
185
+ }
@@ -0,0 +1,4 @@
1
+ // Render nothing in native for now.
2
+ export default function ContentOnlySettingsMenu() {
3
+ return null;
4
+ }
@@ -0,0 +1,6 @@
1
+ @use "@wordpress/base-styles/variables" as *;
2
+
3
+ .editor-content-only-settings-menu__description {
4
+ padding: $grid-unit;
5
+ min-width: 235px;
6
+ }
@@ -1,3 +1,7 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import clsx from 'clsx';
1
5
  /**
2
6
  * WordPress dependencies
3
7
  */
@@ -18,7 +22,7 @@ import {
18
22
  import { unlock } from '../../lock-unlock';
19
23
  import CommentAuthorInfo from './comment-author-info';
20
24
  import CommentForm from './comment-form';
21
- import { focusCommentThread } from './utils';
25
+ import { focusCommentThread, noop } from './utils';
22
26
 
23
27
  const { useBlockElement } = unlock( blockEditorPrivateApis );
24
28
 
@@ -27,6 +31,10 @@ export function AddComment( {
27
31
  showCommentBoard,
28
32
  setShowCommentBoard,
29
33
  commentSidebarRef,
34
+ reflowComments = noop,
35
+ isFloating = false,
36
+ y,
37
+ refs,
30
38
  } ) {
31
39
  const { clientId, blockCommentId } = useSelect( ( select ) => {
32
40
  const { getSelectedBlock } = select( blockEditorStore );
@@ -44,10 +52,29 @@ export function AddComment( {
44
52
 
45
53
  return (
46
54
  <VStack
47
- className="editor-collab-sidebar-panel__thread is-selected"
55
+ className={ clsx(
56
+ 'editor-collab-sidebar-panel__thread is-selected',
57
+ {
58
+ 'is-floating': isFloating,
59
+ }
60
+ ) }
48
61
  spacing="3"
49
62
  tabIndex={ 0 }
63
+ aria-label={ __( 'New note' ) }
50
64
  role="listitem"
65
+ ref={ isFloating ? refs.setFloating : undefined }
66
+ style={
67
+ isFloating
68
+ ? // Delay showing the floating note box until a Y position is known to prevent blink.
69
+ { top: y, opacity: ! y ? 0 : undefined }
70
+ : undefined
71
+ }
72
+ onBlur={ ( event ) => {
73
+ if ( event.currentTarget.contains( event.relatedTarget ) ) {
74
+ return;
75
+ }
76
+ setShowCommentBoard( false );
77
+ } }
51
78
  >
52
79
  <HStack alignment="left" spacing="3">
53
80
  <CommentAuthorInfo />
@@ -62,8 +89,9 @@ export function AddComment( {
62
89
  setShowCommentBoard( false );
63
90
  blockElement?.focus();
64
91
  } }
92
+ reflowComments={ reflowComments }
65
93
  submitButtonText={ __( 'Add note' ) }
66
- labelText={ __( 'New Note' ) }
94
+ labelText={ __( 'New note' ) }
67
95
  />
68
96
  </VStack>
69
97
  );
@@ -6,11 +6,6 @@ import { __, _n, sprintf } from '@wordpress/i18n';
6
6
  import { useMemo } from '@wordpress/element';
7
7
  import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor';
8
8
 
9
- /**
10
- * External dependencies
11
- */
12
- import clsx from 'clsx';
13
-
14
9
  /**
15
10
  * Internal dependencies
16
11
  */
@@ -19,7 +14,7 @@ import { getAvatarBorderColor } from './utils';
19
14
 
20
15
  const { CommentIconToolbarSlotFill } = unlock( blockEditorPrivateApis );
21
16
 
22
- const CommentAvatarIndicator = ( { onClick, thread, hasMoreComments } ) => {
17
+ const CommentAvatarIndicator = ( { onClick, thread } ) => {
23
18
  const threadParticipants = useMemo( () => {
24
19
  if ( ! thread ) {
25
20
  return [];
@@ -34,15 +29,13 @@ const CommentAvatarIndicator = ( { onClick, thread, hasMoreComments } ) => {
34
29
  allComments.forEach( ( comment ) => {
35
30
  // Track thread participants (original commenter + repliers).
36
31
  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, {
32
+ if ( ! participantsMap.has( comment.author ) ) {
33
+ participantsMap.set( comment.author, {
40
34
  name: comment.author_name,
41
35
  avatar:
42
36
  comment.author_avatar_urls?.[ '48' ] ||
43
37
  comment.author_avatar_urls?.[ '96' ],
44
38
  id: comment.author,
45
- isOriginalCommenter: comment.id === thread.id,
46
39
  date: comment.date,
47
40
  } );
48
41
  }
@@ -52,14 +45,6 @@ const CommentAvatarIndicator = ( { onClick, thread, hasMoreComments } ) => {
52
45
  return Array.from( participantsMap.values() );
53
46
  }, [ thread ] );
54
47
 
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
48
  if ( ! threadParticipants.length ) {
64
49
  return null;
65
50
  }
@@ -68,6 +53,7 @@ const CommentAvatarIndicator = ( { onClick, thread, hasMoreComments } ) => {
68
53
  const maxAvatars = 3;
69
54
  const visibleParticipants = threadParticipants.slice( 0, maxAvatars );
70
55
  const overflowCount = Math.max( 0, threadParticipants.length - maxAvatars );
56
+ const threadHasMoreParticipants = threadParticipants.length > 100;
71
57
 
72
58
  // If we hit the comment limit, show "100+" instead of exact overflow count.
73
59
  const overflowText =
@@ -95,9 +81,7 @@ const CommentAvatarIndicator = ( { onClick, thread, hasMoreComments } ) => {
95
81
  return (
96
82
  <CommentIconToolbarSlotFill.Fill>
97
83
  <ToolbarButton
98
- className={ clsx( 'comment-avatar-indicator', {
99
- 'has-unresolved': hasUnresolved,
100
- } ) }
84
+ className="comment-avatar-indicator"
101
85
  label={ __( 'View notes' ) }
102
86
  onClick={ onClick }
103
87
  showTooltip
@@ -105,7 +89,7 @@ const CommentAvatarIndicator = ( { onClick, thread, hasMoreComments } ) => {
105
89
  <div className="comment-avatar-stack">
106
90
  { visibleParticipants.map( ( participant, index ) => (
107
91
  <img
108
- key={ participant.name + index }
92
+ key={ participant.id }
109
93
  src={ participant.avatar }
110
94
  alt={ participant.name }
111
95
  className="comment-avatar"
@@ -6,7 +6,13 @@ 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
+ } from '@wordpress/element';
10
16
  import {
11
17
  __experimentalText as Text,
12
18
  __experimentalHStack as HStack,
@@ -33,32 +39,19 @@ import {
33
39
  import { unlock } from '../../lock-unlock';
34
40
  import CommentAuthorInfo from './comment-author-info';
35
41
  import CommentForm from './comment-form';
36
- import { getCommentExcerpt, focusCommentThread } from './utils';
42
+ import { focusCommentThread, getCommentExcerpt } from './utils';
37
43
  import { useFloatingThread } from './hooks';
44
+ import { AddComment } from './add-comment';
38
45
 
39
46
  const { useBlockElement } = unlock( blockEditorPrivateApis );
40
47
  const { Menu } = unlock( componentsPrivateApis );
41
48
 
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
49
  export function Comments( {
58
- threads,
50
+ threads: noteThreads,
59
51
  onEditComment,
60
52
  onAddReply,
61
53
  onCommentDelete,
54
+ showCommentBoard,
62
55
  setShowCommentBoard,
63
56
  commentSidebarRef,
64
57
  reflowComments,
@@ -70,20 +63,62 @@ export function Comments( {
70
63
  const [ boardOffsets, setBoardOffsets ] = useState( {} );
71
64
  const [ blockRefs, setBlockRefs ] = useState( {} );
72
65
 
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
- }, [] );
66
+ const { blockCommentId, selectedBlockClientId, orderedBlockIds } =
67
+ useSelect( ( select ) => {
68
+ const { getBlockAttributes, getSelectedBlockClientId } =
69
+ select( blockEditorStore );
70
+ const clientId = getSelectedBlockClientId();
71
+ return {
72
+ blockCommentId: clientId
73
+ ? getBlockAttributes( clientId )?.metadata?.noteId
74
+ : null,
75
+ selectedBlockClientId: clientId,
76
+ orderedBlockIds: select( blockEditorStore ).getBlockOrder(),
77
+ };
78
+ }, [] );
84
79
 
85
80
  const relatedBlockElement = useBlockElement( selectedBlockClientId );
86
81
 
82
+ const threads = useMemo( () => {
83
+ const t = [ ...noteThreads ];
84
+ const orderedThreads = [];
85
+ // In floating mode, when the note board is shown, and as long
86
+ // as the selected block doesn't have an existing note attached -
87
+ // add a "new note" entry to the threads. This special thread type
88
+ // gets sorted and floated like regular threads, but shows an AddComment
89
+ // component instead of a regular comment thread.
90
+ if ( isFloating && showCommentBoard && undefined === blockCommentId ) {
91
+ // Insert the new note entry at the correct location for its blockId.
92
+ const newNoteThread = {
93
+ id: 'new-note-thread',
94
+ blockClientId: selectedBlockClientId,
95
+ content: { rendered: '' },
96
+ };
97
+ // Insert the new comment block at the right order within the threads.
98
+ orderedBlockIds.forEach( ( blockId ) => {
99
+ if ( blockId === selectedBlockClientId ) {
100
+ orderedThreads.push( newNoteThread );
101
+ } else {
102
+ const threadForBlock = t.find(
103
+ ( thread ) => thread.blockClientId === blockId
104
+ );
105
+ if ( threadForBlock ) {
106
+ orderedThreads.push( threadForBlock );
107
+ }
108
+ }
109
+ } );
110
+ return orderedThreads;
111
+ }
112
+ return t;
113
+ }, [
114
+ noteThreads,
115
+ isFloating,
116
+ showCommentBoard,
117
+ blockCommentId,
118
+ selectedBlockClientId,
119
+ orderedBlockIds,
120
+ ] );
121
+
87
122
  const handleDelete = async ( comment ) => {
88
123
  const currentIndex = threads.findIndex( ( t ) => t.id === comment.id );
89
124
  const nextThread = threads[ currentIndex + 1 ];
@@ -247,17 +282,33 @@ export function Comments( {
247
282
  const hasThreads = Array.isArray( threads ) && threads.length > 0;
248
283
  if ( ! hasThreads && ! isFloating ) {
249
284
  return (
250
- <VStack alignment="left" justify="flex-start" spacing="2">
285
+ <>
286
+ <AddComment
287
+ onSubmit={ onAddReply }
288
+ showCommentBoard={ showCommentBoard }
289
+ setShowCommentBoard={ setShowCommentBoard }
290
+ commentSidebarRef={ commentSidebarRef }
291
+ />
251
292
  <Text as="p">{ __( 'No notes available.' ) }</Text>
252
293
  <Text as="p" variant="muted">
253
294
  { __( 'Only logged in users can see Notes.' ) }
254
295
  </Text>
255
- </VStack>
296
+ </>
256
297
  );
257
298
  }
258
299
 
259
300
  return (
260
- <VStack spacing="3">
301
+ <>
302
+ { ! isFloating &&
303
+ showCommentBoard &&
304
+ undefined === blockCommentId && (
305
+ <AddComment
306
+ onSubmit={ onAddReply }
307
+ showCommentBoard={ showCommentBoard }
308
+ setShowCommentBoard={ setShowCommentBoard }
309
+ commentSidebarRef={ commentSidebarRef }
310
+ />
311
+ ) }
261
312
  { threads.map( ( thread ) => (
262
313
  <Thread
263
314
  key={ thread.id }
@@ -276,9 +327,10 @@ export function Comments( {
276
327
  setBlockRef={ setBlockRef }
277
328
  selectedThread={ selectedThread }
278
329
  commentLastUpdated={ commentLastUpdated }
330
+ showCommentBoard={ showCommentBoard }
279
331
  />
280
332
  ) ) }
281
- </VStack>
333
+ </>
282
334
  );
283
335
  }
284
336
 
@@ -298,6 +350,7 @@ function Thread( {
298
350
  setSelectedThread,
299
351
  selectedThread,
300
352
  commentLastUpdated,
353
+ showCommentBoard,
301
354
  } ) {
302
355
  const { toggleBlockHighlight, selectBlock, toggleBlockSpotlight } = unlock(
303
356
  useDispatch( blockEditorStore )
@@ -347,7 +400,7 @@ function Thread( {
347
400
  const restReplies = allReplies.length > 0 ? allReplies.slice( 0, -1 ) : [];
348
401
 
349
402
  const commentExcerpt = getCommentExcerpt(
350
- stripHTML( thread.content.rendered ),
403
+ stripHTML( thread.content?.rendered ),
351
404
  10
352
405
  );
353
406
  const ariaLabel = !! thread.blockClientId
@@ -362,6 +415,21 @@ function Thread( {
362
415
  commentExcerpt
363
416
  );
364
417
 
418
+ if ( 'new-note-thread' === thread.id && showCommentBoard && isFloating ) {
419
+ return (
420
+ <AddComment
421
+ onSubmit={ onAddReply }
422
+ showCommentBoard={ showCommentBoard }
423
+ setShowCommentBoard={ setShowCommentBoard }
424
+ commentSidebarRef={ commentSidebarRef }
425
+ reflowComments={ reflowComments }
426
+ isFloating={ isFloating }
427
+ y={ y }
428
+ refs={ refs }
429
+ />
430
+ );
431
+ }
432
+
365
433
  return (
366
434
  // Disable reason: role="listitem" does in fact support aria-expanded.
367
435
  // eslint-disable-next-line jsx-a11y/role-supports-aria-props
@@ -378,6 +446,9 @@ function Thread( {
378
446
  onFocus={ onMouseEnter }
379
447
  onBlur={ onMouseLeave }
380
448
  onKeyDown={ ( event ) => {
449
+ if ( event.defaultPrevented ) {
450
+ return;
451
+ }
381
452
  // Expand or Collapse thread.
382
453
  if (
383
454
  event.key === 'Enter' &&
@@ -745,7 +816,9 @@ const CommentBoard = ( {
745
816
  onCancel={ handleCancel }
746
817
  confirmButtonText={ __( 'Delete' ) }
747
818
  >
748
- { __( 'Are you sure you want to delete this note?' ) }
819
+ { __(
820
+ "Are you sure you want to delete this note? This will also delete all of this note's replies."
821
+ ) }
749
822
  </ConfirmDialog>
750
823
  ) }
751
824
  </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,
@@ -160,7 +160,6 @@ export function useBlockComments( postId ) {
160
160
  return {
161
161
  resultComments,
162
162
  unresolvedSortedThreads,
163
- totalPages,
164
163
  reflowComments,
165
164
  commentLastUpdated,
166
165
  };
@@ -399,7 +398,7 @@ export function useFloatingThread( {
399
398
  if ( blockRef.current ) {
400
399
  refs.setReference( blockRef.current );
401
400
  }
402
- }, [ blockRef, refs ] );
401
+ }, [ blockRef, refs, commentLastUpdated ] );
403
402
 
404
403
  // Track thread heights.
405
404
  useEffect( () => {