@wordpress/editor 14.30.0 → 14.30.1-next.6f42e1382.0

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 (41) hide show
  1. package/build/bindings/api.js +2 -0
  2. package/build/bindings/api.js.map +1 -1
  3. package/build/bindings/term-data.js +171 -0
  4. package/build/bindings/term-data.js.map +1 -0
  5. package/build/components/collab-sidebar/add-comment.js +6 -3
  6. package/build/components/collab-sidebar/add-comment.js.map +1 -1
  7. package/build/components/collab-sidebar/comment-form.js +17 -6
  8. package/build/components/collab-sidebar/comment-form.js.map +1 -1
  9. package/build/components/collab-sidebar/index.js +8 -11
  10. package/build/components/collab-sidebar/index.js.map +1 -1
  11. package/build/components/post-taxonomies/hierarchical-term-selector.js +21 -9
  12. package/build/components/post-taxonomies/hierarchical-term-selector.js.map +1 -1
  13. package/build-module/bindings/api.js +2 -0
  14. package/build-module/bindings/api.js.map +1 -1
  15. package/build-module/bindings/term-data.js +165 -0
  16. package/build-module/bindings/term-data.js.map +1 -0
  17. package/build-module/components/collab-sidebar/add-comment.js +6 -3
  18. package/build-module/components/collab-sidebar/add-comment.js.map +1 -1
  19. package/build-module/components/collab-sidebar/comment-form.js +17 -7
  20. package/build-module/components/collab-sidebar/comment-form.js.map +1 -1
  21. package/build-module/components/collab-sidebar/index.js +8 -11
  22. package/build-module/components/collab-sidebar/index.js.map +1 -1
  23. package/build-module/components/post-taxonomies/hierarchical-term-selector.js +21 -11
  24. package/build-module/components/post-taxonomies/hierarchical-term-selector.js.map +1 -1
  25. package/build-types/bindings/api.d.ts.map +1 -1
  26. package/build-types/bindings/term-data.d.ts +25 -0
  27. package/build-types/bindings/term-data.d.ts.map +1 -0
  28. package/build-types/components/collab-sidebar/add-comment.d.ts.map +1 -1
  29. package/build-types/components/collab-sidebar/comment-form.d.ts.map +1 -1
  30. package/build-types/components/collab-sidebar/index.d.ts +1 -1
  31. package/build-types/components/collab-sidebar/index.d.ts.map +1 -1
  32. package/build-types/components/post-taxonomies/hierarchical-term-selector.d.ts +10 -1
  33. package/build-types/components/post-taxonomies/hierarchical-term-selector.d.ts.map +1 -1
  34. package/package.json +37 -37
  35. package/src/bindings/api.js +2 -0
  36. package/src/bindings/term-data.js +159 -0
  37. package/src/components/collab-sidebar/add-comment.js +20 -9
  38. package/src/components/collab-sidebar/comment-form.js +20 -8
  39. package/src/components/collab-sidebar/index.js +15 -14
  40. package/src/components/post-taxonomies/hierarchical-term-selector.js +25 -8
  41. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,159 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __ } from '@wordpress/i18n';
5
+ import { store as coreDataStore } from '@wordpress/core-data';
6
+
7
+ /**
8
+ * Creates the data fields object with the given term data values and ID value.
9
+ *
10
+ * @param {Object} termDataValues The term data values.
11
+ * @param {string|number} idValue The ID value to use.
12
+ * @return {Object} The data fields object.
13
+ */
14
+ function createDataFields( termDataValues, idValue ) {
15
+ return {
16
+ id: {
17
+ label: __( 'Term ID' ),
18
+ value: idValue,
19
+ type: 'string',
20
+ },
21
+ name: {
22
+ label: __( 'Name' ),
23
+ value: termDataValues?.name,
24
+ type: 'string',
25
+ },
26
+ slug: {
27
+ label: __( 'Slug' ),
28
+ value: termDataValues?.slug,
29
+ type: 'string',
30
+ },
31
+ link: {
32
+ label: __( 'Link' ),
33
+ value: termDataValues?.link,
34
+ type: 'string',
35
+ },
36
+ description: {
37
+ label: __( 'Description' ),
38
+ value: termDataValues?.description,
39
+ type: 'string',
40
+ },
41
+ parent: {
42
+ label: __( 'Parent ID' ),
43
+ value: termDataValues?.parent,
44
+ type: 'string',
45
+ },
46
+ count: {
47
+ label: __( 'Count' ),
48
+ value: `(${ termDataValues?.count ?? 0 })`,
49
+ type: 'string',
50
+ },
51
+ };
52
+ }
53
+
54
+ /**
55
+ * Gets a list of term data fields with their values and labels
56
+ * to be consumed in the needed callbacks.
57
+ * If the value is not available based on context, like in templates,
58
+ * it falls back to the default value, label, or key.
59
+ *
60
+ * @param {Object} select The select function from the data store.
61
+ * @param {Object} context The context provided.
62
+ * @return {Object} List of term data fields with their value and label.
63
+ *
64
+ * @example
65
+ * ```js
66
+ * {
67
+ * name: {
68
+ * label: 'Term Name',
69
+ * value: 'Category Name',
70
+ * },
71
+ * count: {
72
+ * label: 'Term Count',
73
+ * value: 5,
74
+ * },
75
+ * ...
76
+ * }
77
+ * ```
78
+ */
79
+ function getTermDataFields( select, context ) {
80
+ const { getEntityRecord } = select( coreDataStore );
81
+
82
+ let termDataValues, dataFields;
83
+ if ( context?.taxonomy && context?.termId ) {
84
+ termDataValues = getEntityRecord(
85
+ 'taxonomy',
86
+ context?.taxonomy,
87
+ context?.termId
88
+ );
89
+
90
+ if ( ! termDataValues && context?.termData ) {
91
+ termDataValues = context.termData;
92
+ }
93
+
94
+ if ( termDataValues ) {
95
+ dataFields = createDataFields( termDataValues, context?.termId );
96
+ }
97
+ } else if ( context?.termData ) {
98
+ termDataValues = context.termData;
99
+ dataFields = createDataFields(
100
+ termDataValues,
101
+ termDataValues?.term_id
102
+ );
103
+ }
104
+
105
+ if ( ! dataFields || ! Object.keys( dataFields ).length ) {
106
+ return null;
107
+ }
108
+
109
+ return dataFields;
110
+ }
111
+
112
+ /**
113
+ * @type {WPBlockBindingsSource}
114
+ */
115
+ export default {
116
+ name: 'core/term-data',
117
+ usesContext: [ 'taxonomy', 'termId', 'termData' ],
118
+ getValues( { select, context, bindings } ) {
119
+ const dataFields = getTermDataFields( select, context );
120
+
121
+ const newValues = {};
122
+ for ( const [ attributeName, source ] of Object.entries( bindings ) ) {
123
+ // Use the value, the field label, or the field key.
124
+ const fieldKey = source.args.key;
125
+ const { value: fieldValue, label: fieldLabel } =
126
+ dataFields?.[ fieldKey ] || {};
127
+ newValues[ attributeName ] = fieldValue ?? fieldLabel ?? fieldKey;
128
+ }
129
+ return newValues;
130
+ },
131
+ // eslint-disable-next-line no-unused-vars
132
+ setValues( { dispatch, context, bindings } ) {
133
+ // Terms are typically not editable through block bindings in most contexts.
134
+ return false;
135
+ },
136
+ canUserEditValue( { select, context, args } ) {
137
+ // Terms are typically read-only when displayed.
138
+ if ( context?.termQuery || context?.termQueryId ) {
139
+ return false;
140
+ }
141
+
142
+ // Lock editing when `taxonomy` or `termId` is not defined.
143
+ if ( ! context?.taxonomy || ! context?.termId ) {
144
+ return false;
145
+ }
146
+
147
+ const fieldValue = getTermDataFields( select, context )?.[ args.key ]
148
+ ?.value;
149
+ // Empty string or `false` could be a valid value, so we need to check if the field value is undefined.
150
+ if ( fieldValue === undefined ) {
151
+ return false;
152
+ }
153
+
154
+ return false;
155
+ },
156
+ getFieldsList( { select, context } ) {
157
+ return getTermDataFields( select, context );
158
+ },
159
+ };
@@ -8,6 +8,7 @@ import {
8
8
  __experimentalVStack as VStack,
9
9
  } from '@wordpress/components';
10
10
  import { store as blockEditorStore } from '@wordpress/block-editor';
11
+ import { isUnmodifiedDefaultBlock } from '@wordpress/blocks';
11
12
 
12
13
  /**
13
14
  * Internal dependencies
@@ -29,16 +30,26 @@ export function AddComment( {
29
30
  showCommentBoard,
30
31
  setShowCommentBoard,
31
32
  } ) {
32
- const { clientId, blockCommentId } = useSelect( ( select ) => {
33
- const { getSelectedBlock } = select( blockEditorStore );
34
- const selectedBlock = getSelectedBlock();
35
- return {
36
- clientId: selectedBlock?.clientId,
37
- blockCommentId: selectedBlock?.attributes?.blockCommentId,
38
- };
39
- } );
33
+ const { clientId, blockCommentId, isEmptyDefaultBlock } = useSelect(
34
+ ( select ) => {
35
+ const { getSelectedBlock } = select( blockEditorStore );
36
+ const selectedBlock = getSelectedBlock();
37
+ return {
38
+ clientId: selectedBlock?.clientId,
39
+ blockCommentId: selectedBlock?.attributes?.blockCommentId,
40
+ isEmptyDefaultBlock: selectedBlock
41
+ ? isUnmodifiedDefaultBlock( selectedBlock )
42
+ : false,
43
+ };
44
+ }
45
+ );
40
46
 
41
- if ( ! showCommentBoard || ! clientId || undefined !== blockCommentId ) {
47
+ if (
48
+ ! showCommentBoard ||
49
+ ! clientId ||
50
+ undefined !== blockCommentId ||
51
+ isEmptyDefaultBlock
52
+ ) {
42
53
  return null;
43
54
  }
44
55
 
@@ -1,3 +1,8 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import TextareaAutosize from 'react-autosize-textarea';
5
+
1
6
  /**
2
7
  * WordPress dependencies
3
8
  */
@@ -5,9 +10,10 @@ import { useState } from '@wordpress/element';
5
10
  import {
6
11
  __experimentalHStack as HStack,
7
12
  Button,
8
- TextareaControl,
13
+ VisuallyHidden,
9
14
  } from '@wordpress/components';
10
15
  import { _x, __ } from '@wordpress/i18n';
16
+ import { useInstanceId } from '@wordpress/compose';
11
17
 
12
18
  /**
13
19
  * Internal dependencies
@@ -29,16 +35,22 @@ function CommentForm( { onSubmit, onCancel, thread, submitButtonText } ) {
29
35
  thread?.content?.raw ?? ''
30
36
  );
31
37
 
38
+ const inputId = useInstanceId( CommentForm, 'comment-input' );
39
+
32
40
  return (
33
41
  <>
34
- <TextareaControl
35
- __next40pxDefaultSize
36
- __nextHasNoMarginBottom
42
+ <VisuallyHidden as="label" htmlFor={ inputId }>
43
+ { __( 'Comment' ) }
44
+ </VisuallyHidden>
45
+ <TextareaAutosize
46
+ id={ inputId }
37
47
  value={ inputComment ?? '' }
38
- onChange={ setInputComment }
39
- label={ __( 'Comment' ) }
40
- hideLabelFromVision
41
- />
48
+ onChange={ ( comment ) =>
49
+ setInputComment( comment.target.value )
50
+ }
51
+ rows={ 4 }
52
+ maxRows={ 20 }
53
+ ></TextareaAutosize>
42
54
  <HStack alignment="left" spacing="3" justify="flex-start">
43
55
  <Button
44
56
  __next40pxDefaultSize
@@ -222,7 +222,7 @@ export default function CollabSidebar() {
222
222
  const { enableComplementaryArea } = useDispatch( interfaceStore );
223
223
  const { getActiveComplementaryArea } = useSelect( interfaceStore );
224
224
 
225
- const { postId, postType, postStatus, threads } = useSelect( ( select ) => {
225
+ const { postId, postType, threads } = useSelect( ( select ) => {
226
226
  const { getCurrentPostId, getCurrentPostType } = select( editorStore );
227
227
  const _postId = getCurrentPostId();
228
228
  const data =
@@ -237,8 +237,6 @@ export default function CollabSidebar() {
237
237
  return {
238
238
  postId: _postId,
239
239
  postType: getCurrentPostType(),
240
- postStatus:
241
- select( editorStore ).getEditedPostAttribute( 'status' ),
242
240
  threads: data,
243
241
  };
244
242
  }, [] );
@@ -257,7 +255,7 @@ export default function CollabSidebar() {
257
255
 
258
256
  const openCollabBoard = () => {
259
257
  setShowCommentBoard( true );
260
- enableComplementaryArea( 'core', 'edit-post/collab-sidebar' );
258
+ enableComplementaryArea( 'core', collabHistorySidebarName );
261
259
  };
262
260
 
263
261
  const [ blocks ] = useEntityBlockEditor( 'postType', postType, {
@@ -265,7 +263,7 @@ export default function CollabSidebar() {
265
263
  } );
266
264
 
267
265
  // Process comments to build the tree structure
268
- const { resultComments, sortedThreads } = useMemo( () => {
266
+ const { resultComments, unresolvedSortedThreads } = useMemo( () => {
269
267
  // Create a compare to store the references to all objects by id
270
268
  const compare = {};
271
269
  const result = [];
@@ -291,7 +289,7 @@ export default function CollabSidebar() {
291
289
  } );
292
290
 
293
291
  if ( 0 === result?.length ) {
294
- return { resultComments: [], sortedThreads: [] };
292
+ return { resultComments: [], unresolvedSortedThreads: [] };
295
293
  }
296
294
 
297
295
  const updatedResult = result.map( ( item ) => ( {
@@ -305,11 +303,18 @@ export default function CollabSidebar() {
305
303
  updatedResult.map( ( thread ) => [ thread.id, thread ] )
306
304
  );
307
305
 
308
- const sortedComments = blockCommentIds
306
+ // Get comments by block order, filter out undefined threads, and exclude resolved comments.
307
+ const unresolvedSortedComments = blockCommentIds
309
308
  .map( ( id ) => threadIdMap.get( id ) )
310
- .filter( ( thread ) => thread !== undefined );
309
+ .filter(
310
+ ( thread ) =>
311
+ thread !== undefined && thread.status !== 'approved'
312
+ );
311
313
 
312
- return { resultComments: updatedResult, sortedThreads: sortedComments };
314
+ return {
315
+ resultComments: updatedResult,
316
+ unresolvedSortedThreads: unresolvedSortedComments,
317
+ };
313
318
  }, [ threads, blocks ] );
314
319
 
315
320
  // Get the global styles to set the background color of the sidebar.
@@ -327,10 +332,6 @@ export default function CollabSidebar() {
327
332
  } );
328
333
  }
329
334
 
330
- if ( postStatus === 'publish' ) {
331
- return null; // or maybe return some message indicating no threads are available.
332
- }
333
-
334
335
  const AddCommentComponent = blockCommentId
335
336
  ? AddCommentToolbarButton
336
337
  : AddCommentButton;
@@ -358,7 +359,7 @@ export default function CollabSidebar() {
358
359
  headerClassName="editor-collab-sidebar__header"
359
360
  >
360
361
  <CollabSidebarContent
361
- comments={ sortedThreads }
362
+ comments={ unresolvedSortedThreads }
362
363
  showCommentBoard={ showCommentBoard }
363
364
  setShowCommentBoard={ setShowCommentBoard }
364
365
  styles={ {
@@ -13,11 +13,15 @@ import {
13
13
  Flex,
14
14
  FlexItem,
15
15
  SearchControl,
16
+ Spinner,
16
17
  privateApis as componentsPrivateApis,
17
18
  } from '@wordpress/components';
18
19
  import { useDispatch, useSelect } from '@wordpress/data';
19
20
  import { useDebounce } from '@wordpress/compose';
20
- import { store as coreStore } from '@wordpress/core-data';
21
+ import {
22
+ store as coreStore,
23
+ privateApis as coreDataPrivateApis,
24
+ } from '@wordpress/core-data';
21
25
  import { speak } from '@wordpress/a11y';
22
26
  import { decodeEntities } from '@wordpress/html-entities';
23
27
 
@@ -28,6 +32,9 @@ import { buildTermsTree } from '../../utils/terms';
28
32
  import { store as editorStore } from '../../store';
29
33
  import { unlock } from '../../lock-unlock';
30
34
 
35
+ const { normalizeTextString } = unlock( componentsPrivateApis );
36
+ const { RECEIVE_INTERMEDIATE_RESULTS } = unlock( coreDataPrivateApis );
37
+
31
38
  /**
32
39
  * Module Constants
33
40
  */
@@ -37,12 +44,11 @@ const DEFAULT_QUERY = {
37
44
  order: 'asc',
38
45
  _fields: 'id,name,parent',
39
46
  context: 'view',
47
+ [ RECEIVE_INTERMEDIATE_RESULTS ]: true,
40
48
  };
41
49
  const MIN_TERMS_COUNT_FOR_FILTER = 8;
42
50
  const EMPTY_ARRAY = [];
43
51
 
44
- const { normalizeTextString } = unlock( componentsPrivateApis );
45
-
46
52
  /**
47
53
  * Sort Terms by Selected.
48
54
  *
@@ -186,14 +192,14 @@ export function HierarchicalTermSelector( { slug } ) {
186
192
 
187
193
  return {
188
194
  hasCreateAction: _taxonomy
189
- ? post._links?.[
195
+ ? !! post._links?.[
190
196
  'wp:action-create-' + _taxonomy.rest_base
191
- ] ?? false
197
+ ]
192
198
  : false,
193
199
  hasAssignAction: _taxonomy
194
- ? post._links?.[
200
+ ? !! post._links?.[
195
201
  'wp:action-assign-' + _taxonomy.rest_base
196
- ] ?? false
202
+ ]
197
203
  : false,
198
204
  terms: _taxonomy
199
205
  ? getEditedPostAttribute( _taxonomy.rest_base )
@@ -410,7 +416,7 @@ export function HierarchicalTermSelector( { slug } ) {
410
416
 
411
417
  return (
412
418
  <Flex direction="column" gap="4">
413
- { showFilter && (
419
+ { showFilter && ! loading && (
414
420
  <SearchControl
415
421
  __next40pxDefaultSize
416
422
  __nextHasNoMarginBottom
@@ -420,6 +426,17 @@ export function HierarchicalTermSelector( { slug } ) {
420
426
  onChange={ setFilter }
421
427
  />
422
428
  ) }
429
+ { loading && (
430
+ <Flex
431
+ justify="center"
432
+ style={ {
433
+ // Match SearchControl height to prevent layout shift.
434
+ height: '40px',
435
+ } }
436
+ >
437
+ <Spinner />
438
+ </Flex>
439
+ ) }
423
440
  <div
424
441
  className="editor-post-taxonomies__hierarchical-terms-list"
425
442
  tabIndex="0"