@wordpress/editor 14.33.3 → 14.33.5

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 (107) hide show
  1. package/build/bindings/post-data.js +47 -63
  2. package/build/bindings/post-data.js.map +3 -3
  3. package/build/bindings/post-meta.js +45 -39
  4. package/build/bindings/post-meta.js.map +2 -2
  5. package/build/components/collab-sidebar/add-comment.js +9 -5
  6. package/build/components/collab-sidebar/add-comment.js.map +2 -2
  7. package/build/components/collab-sidebar/comment-author-info.js +27 -15
  8. package/build/components/collab-sidebar/comment-author-info.js.map +2 -2
  9. package/build/components/collab-sidebar/comment-indicator-toolbar.js +9 -23
  10. package/build/components/collab-sidebar/comment-indicator-toolbar.js.map +3 -3
  11. package/build/components/collab-sidebar/comment-menu-item.js +36 -6
  12. package/build/components/collab-sidebar/comment-menu-item.js.map +3 -3
  13. package/build/components/collab-sidebar/comments.js +317 -301
  14. package/build/components/collab-sidebar/comments.js.map +3 -3
  15. package/build/components/collab-sidebar/hooks.js +5 -3
  16. package/build/components/collab-sidebar/hooks.js.map +2 -2
  17. package/build/components/collab-sidebar/index.js +35 -11
  18. package/build/components/collab-sidebar/index.js.map +3 -3
  19. package/build/components/collab-sidebar/utils.js +6 -3
  20. package/build/components/collab-sidebar/utils.js.map +2 -2
  21. package/build/components/editor/index.js +2 -2
  22. package/build/components/editor/index.js.map +3 -3
  23. package/build/components/more-menu/index.js +1 -1
  24. package/build/components/more-menu/index.js.map +2 -2
  25. package/build/components/visual-editor/index.js +20 -9
  26. package/build/components/visual-editor/index.js.map +2 -2
  27. package/build/store/private-actions.js +8 -0
  28. package/build/store/private-actions.js.map +2 -2
  29. package/build/store/private-selectors.js +5 -0
  30. package/build/store/private-selectors.js.map +2 -2
  31. package/build/store/reducer.js +10 -0
  32. package/build/store/reducer.js.map +2 -2
  33. package/build-module/bindings/post-data.js +47 -63
  34. package/build-module/bindings/post-data.js.map +2 -2
  35. package/build-module/bindings/post-meta.js +45 -39
  36. package/build-module/bindings/post-meta.js.map +2 -2
  37. package/build-module/components/collab-sidebar/add-comment.js +10 -6
  38. package/build-module/components/collab-sidebar/add-comment.js.map +2 -2
  39. package/build-module/components/collab-sidebar/comment-author-info.js +27 -15
  40. package/build-module/components/collab-sidebar/comment-author-info.js.map +2 -2
  41. package/build-module/components/collab-sidebar/comment-indicator-toolbar.js +15 -25
  42. package/build-module/components/collab-sidebar/comment-indicator-toolbar.js.map +2 -2
  43. package/build-module/components/collab-sidebar/comment-menu-item.js +40 -7
  44. package/build-module/components/collab-sidebar/comment-menu-item.js.map +2 -2
  45. package/build-module/components/collab-sidebar/comments.js +319 -302
  46. package/build-module/components/collab-sidebar/comments.js.map +2 -2
  47. package/build-module/components/collab-sidebar/hooks.js +5 -3
  48. package/build-module/components/collab-sidebar/hooks.js.map +2 -2
  49. package/build-module/components/collab-sidebar/index.js +35 -11
  50. package/build-module/components/collab-sidebar/index.js.map +2 -2
  51. package/build-module/components/collab-sidebar/utils.js +6 -3
  52. package/build-module/components/collab-sidebar/utils.js.map +2 -2
  53. package/build-module/components/editor/index.js +2 -2
  54. package/build-module/components/editor/index.js.map +2 -2
  55. package/build-module/components/more-menu/index.js +1 -1
  56. package/build-module/components/more-menu/index.js.map +2 -2
  57. package/build-module/components/visual-editor/index.js +20 -9
  58. package/build-module/components/visual-editor/index.js.map +2 -2
  59. package/build-module/store/private-actions.js +7 -0
  60. package/build-module/store/private-actions.js.map +2 -2
  61. package/build-module/store/private-selectors.js +4 -0
  62. package/build-module/store/private-selectors.js.map +2 -2
  63. package/build-module/store/reducer.js +9 -0
  64. package/build-module/store/reducer.js.map +2 -2
  65. package/build-style/style-rtl.css +6 -43
  66. package/build-style/style.css +6 -43
  67. package/build-types/bindings/post-data.d.ts +18 -8
  68. package/build-types/bindings/post-meta.d.ts +1 -7
  69. package/build-types/components/collab-sidebar/add-comment.d.ts.map +1 -1
  70. package/build-types/components/collab-sidebar/comment-author-info.d.ts +5 -16
  71. package/build-types/components/collab-sidebar/comment-author-info.d.ts.map +1 -1
  72. package/build-types/components/collab-sidebar/comment-indicator-toolbar.d.ts.map +1 -1
  73. package/build-types/components/collab-sidebar/comment-menu-item.d.ts +3 -2
  74. package/build-types/components/collab-sidebar/comment-menu-item.d.ts.map +1 -1
  75. package/build-types/components/collab-sidebar/comments.d.ts +1 -1
  76. package/build-types/components/collab-sidebar/comments.d.ts.map +1 -1
  77. package/build-types/components/collab-sidebar/hooks.d.ts.map +1 -1
  78. package/build-types/components/collab-sidebar/index.d.ts.map +1 -1
  79. package/build-types/components/collab-sidebar/utils.d.ts +2 -2
  80. package/build-types/components/collab-sidebar/utils.d.ts.map +1 -1
  81. package/build-types/components/visual-editor/index.d.ts.map +1 -1
  82. package/build-types/store/private-actions.d.ts +7 -0
  83. package/build-types/store/private-actions.d.ts.map +1 -1
  84. package/build-types/store/private-selectors.d.ts +7 -0
  85. package/build-types/store/private-selectors.d.ts.map +1 -1
  86. package/build-types/store/reducer.d.ts +10 -0
  87. package/build-types/store/reducer.d.ts.map +1 -1
  88. package/package.json +8 -8
  89. package/src/bindings/post-data.js +63 -111
  90. package/src/bindings/post-meta.js +55 -46
  91. package/src/bindings/test/post-meta.js +211 -0
  92. package/src/components/collab-sidebar/add-comment.js +11 -6
  93. package/src/components/collab-sidebar/comment-author-info.js +33 -26
  94. package/src/components/collab-sidebar/comment-indicator-toolbar.js +19 -29
  95. package/src/components/collab-sidebar/comment-menu-item.js +51 -11
  96. package/src/components/collab-sidebar/comments.js +47 -27
  97. package/src/components/collab-sidebar/hooks.js +6 -4
  98. package/src/components/collab-sidebar/index.js +63 -27
  99. package/src/components/collab-sidebar/style.scss +6 -46
  100. package/src/components/collab-sidebar/utils.js +15 -5
  101. package/src/components/editor/index.js +1 -1
  102. package/src/components/more-menu/index.js +1 -1
  103. package/src/components/visual-editor/index.js +27 -6
  104. package/src/store/private-actions.js +13 -0
  105. package/src/store/private-selectors.js +10 -0
  106. package/src/store/reducer.js +16 -0
  107. package/tsconfig.tsbuildinfo +1 -1
@@ -1,8 +1,12 @@
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
 
@@ -49,10 +53,16 @@ const CommentAvatarIndicator = ( { onClick, thread } ) => {
49
53
  return null;
50
54
  }
51
55
 
52
- // Show up to 3 avatars, with overflow indicator.
56
+ // If there are more than 3 participants, show 2 avatars and a "+n" number.
53
57
  const maxAvatars = 3;
54
- const visibleParticipants = threadParticipants.slice( 0, maxAvatars );
55
- 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
+ );
56
66
  const threadHasMoreParticipants = threadParticipants.length > 100;
57
67
 
58
68
  // If we hit the comment limit, show "100+" instead of exact overflow count.
@@ -65,19 +75,6 @@ const CommentAvatarIndicator = ( { onClick, thread } ) => {
65
75
  overflowCount
66
76
  );
67
77
 
68
- const overflowTitle =
69
- threadHasMoreParticipants && overflowCount > 0
70
- ? __( '100+ participants' )
71
- : sprintf(
72
- // translators: %s: Number of participants.
73
- _n(
74
- '+%s more participant',
75
- '+%s more participants',
76
- overflowCount
77
- ),
78
- overflowCount
79
- );
80
-
81
78
  return (
82
79
  <CommentIconToolbarSlotFill.Fill>
83
80
  <ToolbarButton
@@ -86,15 +83,14 @@ const CommentAvatarIndicator = ( { onClick, thread } ) => {
86
83
  onClick={ onClick }
87
84
  showTooltip
88
85
  >
89
- <div className="comment-avatar-stack">
90
- { visibleParticipants.map( ( participant, index ) => (
86
+ <HStack spacing="1">
87
+ { visibleParticipants.map( ( participant ) => (
91
88
  <img
92
89
  key={ participant.id }
93
90
  src={ participant.avatar }
94
91
  alt={ participant.name }
95
92
  className="comment-avatar"
96
93
  style={ {
97
- zIndex: maxAvatars - index,
98
94
  borderColor: getAvatarBorderColor(
99
95
  participant.id
100
96
  ),
@@ -102,15 +98,9 @@ const CommentAvatarIndicator = ( { onClick, thread } ) => {
102
98
  />
103
99
  ) ) }
104
100
  { overflowCount > 0 && (
105
- <div
106
- className="comment-avatar-overflow"
107
- style={ { zIndex: 0 } }
108
- title={ overflowTitle }
109
- >
110
- { overflowText }
111
- </div>
101
+ <Text weight={ 500 }>{ overflowText }</Text>
112
102
  ) }
113
- </div>
103
+ </HStack>
114
104
  </ToolbarButton>
115
105
  </CommentIconToolbarSlotFill.Fill>
116
106
  );
@@ -4,8 +4,12 @@
4
4
  import { MenuItem } from '@wordpress/components';
5
5
  import { __ } from '@wordpress/i18n';
6
6
  import { comment as commentIcon } from '@wordpress/icons';
7
-
8
- import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor';
7
+ import {
8
+ privateApis as blockEditorPrivateApis,
9
+ store as blockEditorStore,
10
+ } from '@wordpress/block-editor';
11
+ import { useSelect } from '@wordpress/data';
12
+ import { getUnregisteredTypeHandlerName } from '@wordpress/blocks';
9
13
 
10
14
  /**
11
15
  * Internal dependencies
@@ -14,23 +18,59 @@ import { unlock } from '../../lock-unlock';
14
18
 
15
19
  const { CommentIconSlotFill } = unlock( blockEditorPrivateApis );
16
20
 
17
- const AddCommentMenuItem = ( { onClick } ) => {
21
+ const AddCommentMenuItem = ( { clientId, onClick, isDistractionFree } ) => {
22
+ const block = useSelect(
23
+ ( select ) => {
24
+ return select( blockEditorStore ).getBlock( clientId );
25
+ },
26
+ [ clientId ]
27
+ );
28
+
29
+ if (
30
+ ! block?.isValid ||
31
+ block?.name === getUnregisteredTypeHandlerName()
32
+ ) {
33
+ return null;
34
+ }
35
+
36
+ const isDisabled = isDistractionFree || block?.name === 'core/freeform';
37
+
38
+ let infoText;
39
+
40
+ if ( isDistractionFree ) {
41
+ infoText = __( 'Notes are disabled in distraction free mode.' );
42
+ } else if ( block?.name === 'core/freeform' ) {
43
+ infoText = __( 'Convert to blocks to add notes.' );
44
+ }
45
+
46
+ return (
47
+ <MenuItem
48
+ icon={ commentIcon }
49
+ onClick={ onClick }
50
+ aria-haspopup="dialog"
51
+ disabled={ isDisabled }
52
+ info={ infoText }
53
+ >
54
+ { __( 'Add note' ) }
55
+ </MenuItem>
56
+ );
57
+ };
58
+
59
+ const AddCommentMenuItemFill = ( { onClick, isDistractionFree } ) => {
18
60
  return (
19
61
  <CommentIconSlotFill.Fill>
20
- { ( { onClose } ) => (
21
- <MenuItem
22
- icon={ commentIcon }
62
+ { ( { clientId, onClose } ) => (
63
+ <AddCommentMenuItem
64
+ clientId={ clientId }
65
+ isDistractionFree={ isDistractionFree }
23
66
  onClick={ () => {
24
67
  onClick();
25
68
  onClose();
26
69
  } }
27
- aria-haspopup="dialog"
28
- >
29
- { __( 'Add note' ) }
30
- </MenuItem>
70
+ />
31
71
  ) }
32
72
  </CommentIconSlotFill.Fill>
33
73
  );
34
74
  };
35
75
 
36
- export default AddCommentMenuItem;
76
+ export default AddCommentMenuItemFill;
@@ -12,6 +12,7 @@ import {
12
12
  useEffect,
13
13
  useCallback,
14
14
  useMemo,
15
+ useRef,
15
16
  } from '@wordpress/element';
16
17
  import {
17
18
  __experimentalText as Text,
@@ -42,6 +43,7 @@ import CommentForm from './comment-form';
42
43
  import { focusCommentThread, getCommentExcerpt } from './utils';
43
44
  import { useFloatingThread } from './hooks';
44
45
  import { AddComment } from './add-comment';
46
+ import { store as editorStore } from '../../store';
45
47
 
46
48
  const { useBlockElement } = unlock( blockEditorPrivateApis );
47
49
  const { Menu } = unlock( componentsPrivateApis );
@@ -63,6 +65,7 @@ export function Comments( {
63
65
  const [ boardOffsets, setBoardOffsets ] = useState( {} );
64
66
  const [ blockRefs, setBlockRefs ] = useState( {} );
65
67
 
68
+ const { setCanvasMinHeight } = unlock( useDispatch( editorStore ) );
66
69
  const { blockCommentId, selectedBlockClientId, orderedBlockIds } =
67
70
  useSelect( ( select ) => {
68
71
  const { getBlockAttributes, getSelectedBlockClientId } =
@@ -149,8 +152,10 @@ export function Comments( {
149
152
 
150
153
  // Auto-select the related comment thread when a block is selected.
151
154
  useEffect( () => {
152
- setSelectedThread( blockCommentId ?? undefined );
153
- }, [ 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 ] );
154
159
 
155
160
  const setBlockRef = useCallback( ( id, blockRef ) => {
156
161
  setBlockRefs( ( prev ) => ( { ...prev, [ id ]: blockRef } ) );
@@ -166,7 +171,7 @@ export function Comments( {
166
171
  const offsets = {};
167
172
 
168
173
  if ( ! isFloating ) {
169
- return offsets;
174
+ return { offsets, minHeight: 0 };
170
175
  }
171
176
 
172
177
  // Find the index of the selected thread.
@@ -184,7 +189,7 @@ export function Comments( {
184
189
  ! selectedThreadData ||
185
190
  ! blockRefs[ selectedThreadData.id ]
186
191
  ) {
187
- return offsets;
192
+ return { offsets, minHeight: 0 };
188
193
  }
189
194
 
190
195
  let blockElement = blockRefs[ selectedThreadData.id ];
@@ -271,30 +276,41 @@ export function Comments( {
271
276
  threadTop: threadTop + additionalOffset,
272
277
  };
273
278
  }
274
- 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 };
275
294
  };
276
- const newOffsets = calculateAllOffsets();
295
+ const { offsets: newOffsets, minHeight } = calculateAllOffsets();
277
296
  if ( Object.keys( newOffsets ).length > 0 ) {
278
297
  setBoardOffsets( newOffsets );
279
298
  }
280
- }, [ 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
+ ] );
281
309
 
282
310
  const hasThreads = Array.isArray( threads ) && threads.length > 0;
311
+ // This should no longer happen since https://github.com/WordPress/gutenberg/pull/72872.
283
312
  if ( ! hasThreads && ! isFloating ) {
284
- return (
285
- <>
286
- <AddComment
287
- onSubmit={ onAddReply }
288
- showCommentBoard={ showCommentBoard }
289
- setShowCommentBoard={ setShowCommentBoard }
290
- commentSidebarRef={ commentSidebarRef }
291
- />
292
- <Text as="p">{ __( 'No notes available.' ) }</Text>
293
- <Text as="p" variant="muted">
294
- { __( 'Only logged in users can see Notes.' ) }
295
- </Text>
296
- </>
297
- );
313
+ return null;
298
314
  }
299
315
 
300
316
  return (
@@ -431,8 +447,6 @@ function Thread( {
431
447
  }
432
448
 
433
449
  return (
434
- // Disable reason: role="listitem" does in fact support aria-expanded.
435
- // eslint-disable-next-line jsx-a11y/role-supports-aria-props
436
450
  <VStack
437
451
  className={ clsx( 'editor-collab-sidebar-panel__thread', {
438
452
  'is-selected': isSelected,
@@ -467,7 +481,7 @@ function Thread( {
467
481
  }
468
482
  } }
469
483
  tabIndex={ 0 }
470
- role="listitem"
484
+ role="treeitem"
471
485
  aria-label={ ariaLabel }
472
486
  aria-expanded={ isSelected }
473
487
  ref={ isFloating ? refs.setFloating : undefined }
@@ -558,7 +572,7 @@ function Thread( {
558
572
  />
559
573
  ) }
560
574
  { isSelected && (
561
- <VStack spacing="2">
575
+ <VStack spacing="2" role="treeitem">
562
576
  <HStack alignment="left" spacing="3" justify="flex-start">
563
577
  <CommentAuthorInfo />
564
578
  </HStack>
@@ -633,7 +647,7 @@ const CommentBoard = ( {
633
647
  } ) => {
634
648
  const [ actionState, setActionState ] = useState( false );
635
649
  const [ showConfirmDialog, setShowConfirmDialog ] = useState( false );
636
-
650
+ const actionButtonRef = useRef( null );
637
651
  const handleConfirmDelete = () => {
638
652
  onDelete( thread );
639
653
  setActionState( false );
@@ -643,6 +657,7 @@ const CommentBoard = ( {
643
657
  const handleCancel = () => {
644
658
  setActionState( false );
645
659
  setShowConfirmDialog( false );
660
+ actionButtonRef.current?.focus();
646
661
  };
647
662
 
648
663
  // Check if this is a resolution comment by checking metadata.
@@ -687,7 +702,10 @@ const CommentBoard = ( {
687
702
  : [];
688
703
 
689
704
  return (
690
- <VStack spacing="2">
705
+ <VStack
706
+ spacing="2"
707
+ role={ thread.parent !== 0 ? 'treeitem' : undefined }
708
+ >
691
709
  <HStack alignment="left" spacing="3" justify="flex-start">
692
710
  <CommentAuthorInfo
693
711
  avatar={ thread?.author_avatar_urls?.[ 48 ] }
@@ -728,6 +746,7 @@ const CommentBoard = ( {
728
746
  <Menu.TriggerButton
729
747
  render={
730
748
  <Button
749
+ ref={ actionButtonRef }
731
750
  size="small"
732
751
  icon={ moreVertical }
733
752
  label={ __( 'Actions' ) }
@@ -761,6 +780,7 @@ const CommentBoard = ( {
761
780
  content: value,
762
781
  } );
763
782
  setActionState( false );
783
+ actionButtonRef.current?.focus();
764
784
  } }
765
785
  onCancel={ () => handleCancel() }
766
786
  thread={ thread }
@@ -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 ] );
@@ -31,6 +31,7 @@ import {
31
31
  } from './hooks';
32
32
  import { focusCommentThread } from './utils';
33
33
  import PostTypeSupportCheck from '../post-type-support-check';
34
+ import { unlock } from '../../lock-unlock';
34
35
 
35
36
  function NotesSidebarContent( {
36
37
  showCommentBoard,
@@ -49,7 +50,7 @@ function NotesSidebarContent( {
49
50
  <VStack
50
51
  className="editor-collab-sidebar-panel"
51
52
  style={ styles }
52
- role="list"
53
+ role="tree"
53
54
  spacing="3"
54
55
  justify="flex-start"
55
56
  ref={ ( node ) => {
@@ -59,6 +60,9 @@ function NotesSidebarContent( {
59
60
  commentSidebarRef.current = node;
60
61
  }
61
62
  } }
63
+ aria-label={
64
+ isFloating ? __( 'Unresolved notes' ) : __( 'All notes' )
65
+ }
62
66
  >
63
67
  <Comments
64
68
  threads={ comments }
@@ -80,19 +84,30 @@ function NotesSidebar( { postId, mode } ) {
80
84
  const [ showCommentBoard, setShowCommentBoard ] = useState( false );
81
85
  const { getActiveComplementaryArea } = useSelect( interfaceStore );
82
86
  const { enableComplementaryArea } = useDispatch( interfaceStore );
87
+ const { toggleBlockSpotlight } = unlock( useDispatch( blockEditorStore ) );
83
88
  const isLargeViewport = useViewportMatch( 'medium' );
84
89
  const commentSidebarRef = useRef( null );
85
90
 
86
91
  const showFloatingSidebar = isLargeViewport && mode === 'post-only';
87
92
 
88
- const blockCommentId = useSelect( ( select ) => {
89
- const { getBlockAttributes, getSelectedBlockClientId } =
90
- select( blockEditorStore );
91
- const clientId = getSelectedBlockClientId();
92
- return clientId
93
- ? getBlockAttributes( clientId )?.metadata?.noteId
94
- : null;
95
- }, [] );
93
+ const { clientId, blockCommentId, isDistractionFree } = useSelect(
94
+ ( select ) => {
95
+ const {
96
+ getBlockAttributes,
97
+ getSelectedBlockClientId,
98
+ getSettings,
99
+ } = select( blockEditorStore );
100
+ const _clientId = getSelectedBlockClientId();
101
+ return {
102
+ clientId: _clientId,
103
+ blockCommentId: _clientId
104
+ ? getBlockAttributes( _clientId )?.metadata?.noteId
105
+ : null,
106
+ isDistractionFree: getSettings().isDistractionFree,
107
+ };
108
+ },
109
+ []
110
+ );
96
111
 
97
112
  const {
98
113
  resultComments,
@@ -113,6 +128,8 @@ function NotesSidebar( { postId, mode } ) {
113
128
  const currentThread = blockCommentId
114
129
  ? resultComments.find( ( thread ) => thread.id === blockCommentId )
115
130
  : null;
131
+ const showAllNotesSidebar =
132
+ resultComments.length > 0 || ! showFloatingSidebar;
116
133
 
117
134
  async function openTheSidebar() {
118
135
  const prevArea = await getActiveComplementaryArea( 'core' );
@@ -142,6 +159,11 @@ function NotesSidebar( { postId, mode } ) {
142
159
  // Focus a comment thread when there's a selected block with a comment.
143
160
  ! blockCommentId ? 'textarea' : undefined
144
161
  );
162
+ toggleBlockSpotlight( clientId, true );
163
+ }
164
+
165
+ if ( isDistractionFree ) {
166
+ return <AddCommentMenuItem isDistractionFree />;
145
167
  }
146
168
 
147
169
  return (
@@ -153,22 +175,29 @@ function NotesSidebar( { postId, mode } ) {
153
175
  />
154
176
  ) }
155
177
  <AddCommentMenuItem onClick={ openTheSidebar } />
156
- <PluginSidebar
157
- identifier={ collabHistorySidebarName }
158
- name={ collabHistorySidebarName }
159
- title={ __( 'Notes' ) }
160
- icon={ commentIcon }
161
- closeLabel={ __( 'Close Notes' ) }
162
- >
163
- <NotesSidebarContent
164
- comments={ resultComments }
165
- showCommentBoard={ showCommentBoard }
166
- setShowCommentBoard={ setShowCommentBoard }
167
- commentSidebarRef={ commentSidebarRef }
168
- reflowComments={ reflowComments }
169
- commentLastUpdated={ commentLastUpdated }
170
- />
171
- </PluginSidebar>
178
+ { showAllNotesSidebar && (
179
+ <PluginSidebar
180
+ identifier={ collabHistorySidebarName }
181
+ name={ collabHistorySidebarName }
182
+ title={ __( 'All notes' ) }
183
+ header={
184
+ <h2 className="interface-complementary-area-header__title">
185
+ { __( 'All notes' ) }
186
+ </h2>
187
+ }
188
+ icon={ commentIcon }
189
+ closeLabel={ __( 'Close Notes' ) }
190
+ >
191
+ <NotesSidebarContent
192
+ comments={ resultComments }
193
+ showCommentBoard={ showCommentBoard }
194
+ setShowCommentBoard={ setShowCommentBoard }
195
+ commentSidebarRef={ commentSidebarRef }
196
+ reflowComments={ reflowComments }
197
+ commentLastUpdated={ commentLastUpdated }
198
+ />
199
+ </PluginSidebar>
200
+ ) }
172
201
  { isLargeViewport && (
173
202
  <PluginSidebar
174
203
  isPinnable={ false }
@@ -197,11 +226,13 @@ function NotesSidebar( { postId, mode } ) {
197
226
  }
198
227
 
199
228
  export default function NotesSidebarContainer() {
200
- const { postId, mode } = useSelect( ( select ) => {
201
- const { getCurrentPostId, getRenderingMode } = select( editorStore );
229
+ const { postId, mode, editorMode } = useSelect( ( select ) => {
230
+ const { getCurrentPostId, getRenderingMode, getEditorMode } =
231
+ select( editorStore );
202
232
  return {
203
233
  postId: getCurrentPostId(),
204
234
  mode: getRenderingMode(),
235
+ editorMode: getEditorMode(),
205
236
  };
206
237
  }, [] );
207
238
 
@@ -209,6 +240,11 @@ export default function NotesSidebarContainer() {
209
240
  return null;
210
241
  }
211
242
 
243
+ // Hide Notes sidebar in Code Editor mode since block-level commenting.
244
+ if ( editorMode === 'text' ) {
245
+ return null;
246
+ }
247
+
212
248
  return (
213
249
  <PostTypeSupportCheck supportKeys="editor.notes">
214
250
  <NotesSidebar postId={ postId } mode={ mode } />
@@ -78,6 +78,7 @@
78
78
  border-width: var(--wp-admin-border-width-focus);
79
79
  border-style: solid;
80
80
  padding: var(--wp-admin-border-width-focus);
81
+ background: $white;
81
82
  }
82
83
 
83
84
  .editor-collab-sidebar-panel__comment-status {
@@ -154,57 +155,16 @@
154
155
  bottom: $grid-unit-10;
155
156
  }
156
157
 
157
- // Comment avatar indicators.
158
- .comment-avatar-indicator {
159
- position: relative;
160
- padding: 4px;
161
- min-width: auto;
162
- background: transparent;
163
- border: none;
164
- }
165
-
166
- .comment-avatar-stack {
167
- display: flex;
168
- align-items: center;
169
- position: relative;
170
- height: $icon-size;
171
- }
172
-
173
158
  .comment-avatar {
174
159
  width: $icon-size;
175
- height: $icon-size;
176
160
  border-radius: $radius-round;
177
- border: 2px solid $white;
178
- margin-left: -6px;
179
- flex-shrink: 0;
161
+ margin-left: -12px;
162
+ border-width: var(--wp-admin-border-width-focus);
163
+ border-style: solid;
164
+ padding: var(--wp-admin-border-width-focus);
165
+ background: $white;
180
166
 
181
167
  &:first-child {
182
168
  margin-left: 0;
183
- border-color: #de6e55;
184
- }
185
-
186
- &:nth-child(2) {
187
- border-color: #599637;
188
- }
189
-
190
- &:nth-child(3) {
191
- border-color: #3858e9;
192
169
  }
193
170
  }
194
-
195
- .comment-avatar-overflow {
196
- width: fit-content;
197
- height: $icon-size;
198
- border-radius: 4rem;
199
- padding: 0 4px;
200
- background: #757575;
201
- color: $white;
202
- border: 2px solid $white;
203
- margin-left: -6px;
204
- display: flex;
205
- align-items: center;
206
- justify-content: center;
207
- font-size: 10px;
208
- font-weight: 600;
209
- flex-shrink: 0;
210
- }
@@ -99,23 +99,32 @@ export function getCommentExcerpt( text, excerptLength = 10 ) {
99
99
  * @typedef {import('@wordpress/element').RefObject} RefObject
100
100
  *
101
101
  * @param {string} commentId The ID of the comment thread to focus.
102
- * @param {?HTMLElement} container The container element to search within.
102
+ * @param {?HTMLElement} threadContainer The container element to search within.
103
103
  * @param {string} additionalSelector The additional selector to focus on.
104
104
  */
105
- export function focusCommentThread( commentId, container, additionalSelector ) {
106
- if ( ! container ) {
105
+ export function focusCommentThread(
106
+ commentId,
107
+ threadContainer,
108
+ additionalSelector
109
+ ) {
110
+ if ( ! threadContainer ) {
107
111
  return;
108
112
  }
109
113
 
110
114
  // A thread without a commentId is a new comment thread.
111
115
  const threadSelector = commentId
112
- ? `[role=listitem][id="comment-thread-${ commentId }"]`
113
- : '[role=listitem]:not([id])';
116
+ ? `[role=treeitem][id="comment-thread-${ commentId }"]`
117
+ : '[role=treeitem]:not([id])';
114
118
  const selector = additionalSelector
115
119
  ? `${ threadSelector } ${ additionalSelector }`
116
120
  : threadSelector;
117
121
 
118
122
  return new Promise( ( resolve ) => {
123
+ // Watch the sidebar skeleton in case the sidebar disappears and re-appears.
124
+ const container = threadContainer.closest(
125
+ '.interface-interface-skeleton__sidebar'
126
+ );
127
+
119
128
  if ( container.querySelector( selector ) ) {
120
129
  return resolve( container.querySelector( selector ) );
121
130
  }
@@ -129,6 +138,7 @@ export function focusCommentThread( commentId, container, additionalSelector ) {
129
138
  resolve( container.querySelector( selector ) );
130
139
  }
131
140
  } );
141
+
132
142
  observer.observe( container, {
133
143
  childList: true,
134
144
  subtree: true,
@@ -87,11 +87,11 @@ function Editor( {
87
87
  { extraContent }
88
88
  </EditorInterface>
89
89
  { children }
90
- <NotesSidebar />
91
90
  <Sidebar
92
91
  onActionPerformed={ onActionPerformed }
93
92
  extraPanels={ extraSidebarPanels }
94
93
  />
94
+ <NotesSidebar />
95
95
  </ExperimentalEditorProvider>
96
96
  ) }
97
97
  </>
@@ -112,7 +112,7 @@ export default function MoreMenu() {
112
112
  <ModeSwitcher />
113
113
  <ActionItem.Slot
114
114
  name="core/plugin-more-menu"
115
- label={ __( 'Plugins' ) }
115
+ label={ __( 'Panels' ) }
116
116
  fillProps={ { onClick: onClose } }
117
117
  />
118
118
  <MenuGroup label={ __( 'Tools' ) }>