@wordpress/dataviews 2.2.0 → 3.0.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 (153) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +5 -5
  3. package/build/add-filter.js +1 -1
  4. package/build/add-filter.js.map +1 -1
  5. package/build/bulk-actions-toolbar.js +0 -1
  6. package/build/bulk-actions-toolbar.js.map +1 -1
  7. package/build/bulk-actions.js +1 -1
  8. package/build/bulk-actions.js.map +1 -1
  9. package/build/dataform.js +78 -0
  10. package/build/dataform.js.map +1 -0
  11. package/build/dataviews.js +17 -28
  12. package/build/dataviews.js.map +1 -1
  13. package/build/filter-and-sort-data-view.js +4 -1
  14. package/build/filter-and-sort-data-view.js.map +1 -1
  15. package/build/filter-summary.js +6 -5
  16. package/build/filter-summary.js.map +1 -1
  17. package/build/filters.js +1 -1
  18. package/build/filters.js.map +1 -1
  19. package/build/index.js +7 -0
  20. package/build/index.js.map +1 -1
  21. package/build/item-actions.js +1 -1
  22. package/build/item-actions.js.map +1 -1
  23. package/build/normalize-fields.js.map +1 -1
  24. package/build/pagination.js +2 -2
  25. package/build/pagination.js.map +1 -1
  26. package/build/private-types.js +6 -0
  27. package/build/private-types.js.map +1 -0
  28. package/build/reset-filters.js +1 -1
  29. package/build/reset-filters.js.map +1 -1
  30. package/build/search-widget.js +8 -6
  31. package/build/search-widget.js.map +1 -1
  32. package/build/single-selection-checkbox.js +5 -16
  33. package/build/single-selection-checkbox.js.map +1 -1
  34. package/build/types.js.map +1 -1
  35. package/build/utils.js.map +1 -1
  36. package/build/view-actions.js +76 -65
  37. package/build/view-actions.js.map +1 -1
  38. package/build/view-grid.js +7 -19
  39. package/build/view-grid.js.map +1 -1
  40. package/build/view-list.js +6 -5
  41. package/build/view-list.js.map +1 -1
  42. package/build/view-table.js +11 -20
  43. package/build/view-table.js.map +1 -1
  44. package/build-module/add-filter.js +1 -1
  45. package/build-module/add-filter.js.map +1 -1
  46. package/build-module/bulk-actions-toolbar.js +0 -1
  47. package/build-module/bulk-actions-toolbar.js.map +1 -1
  48. package/build-module/bulk-actions.js +1 -1
  49. package/build-module/bulk-actions.js.map +1 -1
  50. package/build-module/dataform.js +72 -0
  51. package/build-module/dataform.js.map +1 -0
  52. package/build-module/dataviews.js +15 -28
  53. package/build-module/dataviews.js.map +1 -1
  54. package/build-module/filter-and-sort-data-view.js +4 -1
  55. package/build-module/filter-and-sort-data-view.js.map +1 -1
  56. package/build-module/filter-summary.js +6 -5
  57. package/build-module/filter-summary.js.map +1 -1
  58. package/build-module/filters.js +1 -1
  59. package/build-module/filters.js.map +1 -1
  60. package/build-module/index.js +1 -0
  61. package/build-module/index.js.map +1 -1
  62. package/build-module/item-actions.js +1 -1
  63. package/build-module/item-actions.js.map +1 -1
  64. package/build-module/normalize-fields.js.map +1 -1
  65. package/build-module/pagination.js +2 -2
  66. package/build-module/pagination.js.map +1 -1
  67. package/build-module/private-types.js +2 -0
  68. package/build-module/private-types.js.map +1 -0
  69. package/build-module/reset-filters.js +1 -1
  70. package/build-module/reset-filters.js.map +1 -1
  71. package/build-module/search-widget.js +8 -6
  72. package/build-module/search-widget.js.map +1 -1
  73. package/build-module/single-selection-checkbox.js +5 -16
  74. package/build-module/single-selection-checkbox.js.map +1 -1
  75. package/build-module/types.js.map +1 -1
  76. package/build-module/utils.js.map +1 -1
  77. package/build-module/view-actions.js +80 -68
  78. package/build-module/view-actions.js.map +1 -1
  79. package/build-module/view-grid.js +7 -19
  80. package/build-module/view-grid.js.map +1 -1
  81. package/build-module/view-list.js +6 -5
  82. package/build-module/view-list.js.map +1 -1
  83. package/build-module/view-table.js +11 -20
  84. package/build-module/view-table.js.map +1 -1
  85. package/build-style/style-rtl.css +8 -24
  86. package/build-style/style.css +8 -24
  87. package/build-types/bulk-actions-toolbar.d.ts +5 -4
  88. package/build-types/bulk-actions-toolbar.d.ts.map +1 -1
  89. package/build-types/bulk-actions.d.ts +7 -6
  90. package/build-types/bulk-actions.d.ts.map +1 -1
  91. package/build-types/dataform.d.ts +17 -0
  92. package/build-types/dataform.d.ts.map +1 -0
  93. package/build-types/dataviews.d.ts +14 -7
  94. package/build-types/dataviews.d.ts.map +1 -1
  95. package/build-types/filter-and-sort-data-view.d.ts +2 -2
  96. package/build-types/filter-and-sort-data-view.d.ts.map +1 -1
  97. package/build-types/filter-summary.d.ts.map +1 -1
  98. package/build-types/filters.d.ts +3 -3
  99. package/build-types/filters.d.ts.map +1 -1
  100. package/build-types/index.d.ts +1 -0
  101. package/build-types/index.d.ts.map +1 -1
  102. package/build-types/item-actions.d.ts +10 -10
  103. package/build-types/item-actions.d.ts.map +1 -1
  104. package/build-types/normalize-fields.d.ts +2 -2
  105. package/build-types/normalize-fields.d.ts.map +1 -1
  106. package/build-types/private-types.d.ts +3 -0
  107. package/build-types/private-types.d.ts.map +1 -0
  108. package/build-types/single-selection-checkbox.d.ts +5 -5
  109. package/build-types/single-selection-checkbox.d.ts.map +1 -1
  110. package/build-types/stories/fixtures.d.ts +14 -1
  111. package/build-types/stories/fixtures.d.ts.map +1 -1
  112. package/build-types/stories/index.story.d.ts +15 -1
  113. package/build-types/stories/index.story.d.ts.map +1 -1
  114. package/build-types/types.d.ts +68 -27
  115. package/build-types/types.d.ts.map +1 -1
  116. package/build-types/utils.d.ts +2 -2
  117. package/build-types/utils.d.ts.map +1 -1
  118. package/build-types/view-actions.d.ts +4 -4
  119. package/build-types/view-actions.d.ts.map +1 -1
  120. package/build-types/view-grid.d.ts +2 -2
  121. package/build-types/view-grid.d.ts.map +1 -1
  122. package/build-types/view-list.d.ts +2 -2
  123. package/build-types/view-list.d.ts.map +1 -1
  124. package/build-types/view-table.d.ts +2 -2
  125. package/build-types/view-table.d.ts.map +1 -1
  126. package/package.json +10 -10
  127. package/src/add-filter.tsx +1 -1
  128. package/src/bulk-actions-toolbar.tsx +13 -13
  129. package/src/bulk-actions.tsx +18 -13
  130. package/src/dataform.tsx +106 -0
  131. package/src/dataviews.tsx +43 -49
  132. package/src/filter-and-sort-data-view.ts +13 -3
  133. package/src/filter-summary.tsx +18 -12
  134. package/src/filters.tsx +4 -4
  135. package/src/index.ts +1 -0
  136. package/src/item-actions.tsx +15 -16
  137. package/src/normalize-fields.ts +5 -3
  138. package/src/pagination.tsx +2 -2
  139. package/src/private-types.tsx +2 -0
  140. package/src/reset-filters.tsx +1 -1
  141. package/src/search-widget.tsx +6 -6
  142. package/src/single-selection-checkbox.tsx +14 -29
  143. package/src/stories/fixtures.js +17 -1
  144. package/src/stories/index.story.js +15 -28
  145. package/src/style.scss +10 -22
  146. package/src/test/filter-and-sort-data-view.js +16 -1
  147. package/src/types.ts +68 -34
  148. package/src/utils.ts +2 -4
  149. package/src/view-actions.tsx +105 -102
  150. package/src/view-grid.tsx +21 -38
  151. package/src/view-list.tsx +12 -15
  152. package/src/view-table.tsx +31 -42
  153. package/tsconfig.tsbuildinfo +1 -1
@@ -14,7 +14,8 @@ import { useRegistry } from '@wordpress/data';
14
14
  * Internal dependencies
15
15
  */
16
16
  import { unlock } from './lock-unlock';
17
- import type { Action, ActionModal, AnyItem } from './types';
17
+ import type { Action, ActionModal } from './types';
18
+ import type { SetSelection } from './private-types';
18
19
 
19
20
  const {
20
21
  DropdownMenuV2: DropdownMenu,
@@ -23,34 +24,34 @@ const {
23
24
  DropdownMenuSeparatorV2: DropdownMenuSeparator,
24
25
  } = unlock( componentsPrivateApis );
25
26
 
26
- interface ActionWithModalProps< Item extends AnyItem > {
27
+ interface ActionWithModalProps< Item > {
27
28
  action: ActionModal< Item >;
28
29
  selectedItems: Item[];
29
30
  setActionWithModal: ( action?: ActionModal< Item > ) => void;
30
31
  onMenuOpenChange: ( isOpen: boolean ) => void;
31
32
  }
32
33
 
33
- interface BulkActionsItemProps< Item extends AnyItem > {
34
+ interface BulkActionsItemProps< Item > {
34
35
  action: Action< Item >;
35
36
  selectedItems: Item[];
36
37
  setActionWithModal: ( action?: ActionModal< Item > ) => void;
37
38
  }
38
39
 
39
- interface ActionsMenuGroupProps< Item extends AnyItem > {
40
+ interface ActionsMenuGroupProps< Item > {
40
41
  actions: Action< Item >[];
41
42
  selectedItems: Item[];
42
43
  setActionWithModal: ( action?: ActionModal< Item > ) => void;
43
44
  }
44
45
 
45
- interface BulkActionsProps< Item extends AnyItem > {
46
+ interface BulkActionsProps< Item > {
46
47
  data: Item[];
47
48
  actions: Action< Item >[];
48
49
  selection: string[];
49
- onSelectionChange: ( selection: Item[] ) => void;
50
+ onSelectionChange: SetSelection;
50
51
  getItemId: ( item: Item ) => string;
51
52
  }
52
53
 
53
- export function useHasAPossibleBulkAction< Item extends AnyItem >(
54
+ export function useHasAPossibleBulkAction< Item >(
54
55
  actions: Action< Item >[],
55
56
  item: Item
56
57
  ) {
@@ -64,7 +65,7 @@ export function useHasAPossibleBulkAction< Item extends AnyItem >(
64
65
  }, [ actions, item ] );
65
66
  }
66
67
 
67
- export function useSomeItemHasAPossibleBulkAction< Item extends AnyItem >(
68
+ export function useSomeItemHasAPossibleBulkAction< Item >(
68
69
  actions: Action< Item >[],
69
70
  data: Item[]
70
71
  ) {
@@ -80,7 +81,7 @@ export function useSomeItemHasAPossibleBulkAction< Item extends AnyItem >(
80
81
  }, [ actions, data ] );
81
82
  }
82
83
 
83
- function ActionWithModal< Item extends AnyItem >( {
84
+ function ActionWithModal< Item >( {
84
85
  action,
85
86
  selectedItems,
86
87
  setActionWithModal,
@@ -115,7 +116,7 @@ function ActionWithModal< Item extends AnyItem >( {
115
116
  );
116
117
  }
117
118
 
118
- function BulkActionItem< Item extends AnyItem >( {
119
+ function BulkActionItem< Item >( {
119
120
  action,
120
121
  selectedItems,
121
122
  setActionWithModal,
@@ -150,7 +151,7 @@ function BulkActionItem< Item extends AnyItem >( {
150
151
  );
151
152
  }
152
153
 
153
- function ActionsMenuGroup< Item extends AnyItem >( {
154
+ function ActionsMenuGroup< Item >( {
154
155
  actions,
155
156
  selectedItems,
156
157
  setActionWithModal,
@@ -172,7 +173,7 @@ function ActionsMenuGroup< Item extends AnyItem >( {
172
173
  );
173
174
  }
174
175
 
175
- export default function BulkActions< Item extends AnyItem >( {
176
+ export default function BulkActions< Item >( {
176
177
  data,
177
178
  actions,
178
179
  selection,
@@ -248,7 +249,11 @@ export default function BulkActions< Item extends AnyItem >( {
248
249
  disabled={ areAllSelected }
249
250
  hideOnClick={ false }
250
251
  onClick={ () => {
251
- onSelectionChange( selectableItems );
252
+ onSelectionChange(
253
+ selectableItems.map( ( item ) =>
254
+ getItemId( item )
255
+ )
256
+ );
252
257
  } }
253
258
  suffix={ numberSelectableItems }
254
259
  >
@@ -0,0 +1,106 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import type { Dispatch, SetStateAction } from 'react';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { TextControl } from '@wordpress/components';
10
+ import { useCallback, useMemo } from '@wordpress/element';
11
+
12
+ /**
13
+ * Internal dependencies
14
+ */
15
+ import type { Form, Field, NormalizedField } from './types';
16
+ import { normalizeFields } from './normalize-fields';
17
+
18
+ type DataFormProps< Item > = {
19
+ data: Item;
20
+ fields: Field< Item >[];
21
+ form: Form;
22
+ onChange: Dispatch< SetStateAction< Item > >;
23
+ };
24
+
25
+ type DataFormControlProps< Item > = {
26
+ data: Item;
27
+ field: NormalizedField< Item >;
28
+ onChange: Dispatch< SetStateAction< Item > >;
29
+ };
30
+
31
+ function DataFormTextControl< Item >( {
32
+ data,
33
+ field,
34
+ onChange,
35
+ }: DataFormControlProps< Item > ) {
36
+ const { id, header, placeholder } = field;
37
+ const value = field.getValue( { item: data } );
38
+
39
+ const onChangeControl = useCallback(
40
+ ( newValue: string ) =>
41
+ onChange( ( prevItem: Item ) => ( {
42
+ ...prevItem,
43
+ [ id ]: newValue,
44
+ } ) ),
45
+ [ id, onChange ]
46
+ );
47
+
48
+ return (
49
+ <TextControl
50
+ label={ header }
51
+ placeholder={ placeholder }
52
+ value={ value }
53
+ onChange={ onChangeControl }
54
+ __next40pxDefaultSize
55
+ />
56
+ );
57
+ }
58
+
59
+ const controls: {
60
+ [ key: string ]: < Item >(
61
+ props: DataFormControlProps< Item >
62
+ ) => JSX.Element;
63
+ } = {
64
+ text: DataFormTextControl,
65
+ };
66
+
67
+ function getControlForField< Item >( field: NormalizedField< Item > ) {
68
+ if ( ! field.type ) {
69
+ return null;
70
+ }
71
+
72
+ if ( ! Object.keys( controls ).includes( field.type ) ) {
73
+ return null;
74
+ }
75
+
76
+ return controls[ field.type ];
77
+ }
78
+
79
+ export default function DataForm< Item >( {
80
+ data,
81
+ fields,
82
+ form,
83
+ onChange,
84
+ }: DataFormProps< Item > ) {
85
+ const visibleFields = useMemo(
86
+ () =>
87
+ normalizeFields(
88
+ fields.filter(
89
+ ( { id } ) => !! form.visibleFields?.includes( id )
90
+ )
91
+ ),
92
+ [ fields, form.visibleFields ]
93
+ );
94
+
95
+ return visibleFields.map( ( field ) => {
96
+ const DataFormControl = getControlForField( field );
97
+ return DataFormControl ? (
98
+ <DataFormControl
99
+ key={ field.id }
100
+ data={ data }
101
+ field={ field }
102
+ onChange={ onChange }
103
+ />
104
+ ) : null;
105
+ } );
106
+ }
package/src/dataviews.tsx CHANGED
@@ -7,7 +7,7 @@ import type { ComponentType } from 'react';
7
7
  * WordPress dependencies
8
8
  */
9
9
  import { __experimentalHStack as HStack } from '@wordpress/components';
10
- import { useMemo, useState, useCallback } from '@wordpress/element';
10
+ import { useMemo, useState } from '@wordpress/element';
11
11
 
12
12
  /**
13
13
  * Internal dependencies
@@ -18,12 +18,24 @@ import Filters from './filters';
18
18
  import Search from './search';
19
19
  import { LAYOUT_TABLE, LAYOUT_GRID } from './constants';
20
20
  import { VIEW_LAYOUTS } from './layouts';
21
- import BulkActions from './bulk-actions';
21
+ import {
22
+ default as BulkActions,
23
+ useSomeItemHasAPossibleBulkAction,
24
+ } from './bulk-actions';
22
25
  import { normalizeFields } from './normalize-fields';
23
26
  import BulkActionsToolbar from './bulk-actions-toolbar';
24
- import type { Action, AnyItem, Field, View, ViewBaseProps } from './types';
27
+ import type {
28
+ Action,
29
+ Field,
30
+ View,
31
+ ViewBaseProps,
32
+ SupportedLayouts,
33
+ } from './types';
34
+ import type { SetSelection, SelectionOrUpdater } from './private-types';
25
35
 
26
- interface DataViewsProps< Item extends AnyItem > {
36
+ type ItemWithId = { id: string };
37
+
38
+ type DataViewsProps< Item > = {
27
39
  view: View;
28
40
  onChangeView: ( view: View ) => void;
29
41
  fields: Field< Item >[];
@@ -31,38 +43,24 @@ interface DataViewsProps< Item extends AnyItem > {
31
43
  searchLabel?: string;
32
44
  actions?: Action< Item >[];
33
45
  data: Item[];
34
- getItemId?: ( item: Item ) => string;
35
46
  isLoading?: boolean;
36
47
  paginationInfo: {
37
48
  totalItems: number;
38
49
  totalPages: number;
39
50
  };
40
- supportedLayouts: string[];
51
+ defaultLayouts: SupportedLayouts;
41
52
  selection?: string[];
42
- setSelection?: ( selection: string[] ) => void;
53
+ setSelection?: SetSelection;
43
54
  onSelectionChange?: ( items: Item[] ) => void;
44
- }
55
+ } & ( Item extends ItemWithId
56
+ ? { getItemId?: ( item: Item ) => string }
57
+ : { getItemId: ( item: Item ) => string } );
45
58
 
46
- const defaultGetItemId = ( item: AnyItem ) => item.id;
47
- const defaultOnSelectionChange = () => {};
59
+ const defaultGetItemId = ( item: ItemWithId ) => item.id;
48
60
 
49
- function useSomeItemHasAPossibleBulkAction< Item extends AnyItem >(
50
- actions: Action< Item >[],
51
- data: Item[]
52
- ) {
53
- return useMemo( () => {
54
- return data.some( ( item ) => {
55
- return actions.some( ( action ) => {
56
- return (
57
- action.supportsBulk &&
58
- ( ! action.isEligible || action.isEligible( item ) )
59
- );
60
- } );
61
- } );
62
- }, [ actions, data ] );
63
- }
61
+ const defaultOnSelectionChange = () => {};
64
62
 
65
- export default function DataViews< Item extends AnyItem >( {
63
+ export default function DataViews< Item >( {
66
64
  view,
67
65
  onChangeView,
68
66
  fields,
@@ -73,32 +71,28 @@ export default function DataViews< Item extends AnyItem >( {
73
71
  getItemId = defaultGetItemId,
74
72
  isLoading = false,
75
73
  paginationInfo,
76
- supportedLayouts,
74
+ defaultLayouts,
77
75
  selection: selectionProperty,
78
76
  setSelection: setSelectionProperty,
79
77
  onSelectionChange = defaultOnSelectionChange,
80
78
  }: DataViewsProps< Item > ) {
81
79
  const [ selectionState, setSelectionState ] = useState< string[] >( [] );
82
- let selection, setSelection;
83
- if (
84
- selectionProperty !== undefined &&
85
- setSelectionProperty !== undefined
86
- ) {
87
- selection = selectionProperty;
88
- setSelection = setSelectionProperty;
89
- } else {
90
- selection = selectionState;
91
- setSelection = setSelectionState;
92
- }
80
+ const isUncontrolled =
81
+ selectionProperty === undefined || setSelectionProperty === undefined;
82
+ const selection = isUncontrolled ? selectionState : selectionProperty;
83
+ const setSelection = isUncontrolled
84
+ ? setSelectionState
85
+ : setSelectionProperty;
93
86
  const [ openedFilter, setOpenedFilter ] = useState< string | null >( null );
94
87
 
95
- const onSetSelection = useCallback(
96
- ( items: Item[] ) => {
97
- setSelection( items.map( ( item ) => getItemId( item ) ) );
98
- onSelectionChange( items );
99
- },
100
- [ setSelection, getItemId, onSelectionChange ]
101
- );
88
+ function setSelectionWithChange( value: SelectionOrUpdater ) {
89
+ const newValue =
90
+ typeof value === 'function' ? value( selection ) : value;
91
+ onSelectionChange(
92
+ data.filter( ( item ) => newValue.includes( getItemId( item ) ) )
93
+ );
94
+ return setSelection( value );
95
+ }
102
96
 
103
97
  const ViewComponent = VIEW_LAYOUTS.find( ( v ) => v.type === view.type )
104
98
  ?.component as ComponentType< ViewBaseProps< Item > >;
@@ -145,7 +139,7 @@ export default function DataViews< Item extends AnyItem >( {
145
139
  <BulkActions
146
140
  actions={ actions }
147
141
  data={ data }
148
- onSelectionChange={ onSetSelection }
142
+ onSelectionChange={ setSelectionWithChange }
149
143
  selection={ _selection }
150
144
  getItemId={ getItemId }
151
145
  />
@@ -154,7 +148,7 @@ export default function DataViews< Item extends AnyItem >( {
154
148
  fields={ _fields }
155
149
  view={ view }
156
150
  onChangeView={ onChangeView }
157
- supportedLayouts={ supportedLayouts }
151
+ defaultLayouts={ defaultLayouts }
158
152
  />
159
153
  </HStack>
160
154
  <ViewComponent
@@ -164,7 +158,7 @@ export default function DataViews< Item extends AnyItem >( {
164
158
  getItemId={ getItemId }
165
159
  isLoading={ isLoading }
166
160
  onChangeView={ onChangeView }
167
- onSelectionChange={ onSetSelection }
161
+ onSelectionChange={ setSelectionWithChange }
168
162
  selection={ _selection }
169
163
  setOpenedFilter={ setOpenedFilter }
170
164
  view={ view }
@@ -180,7 +174,7 @@ export default function DataViews< Item extends AnyItem >( {
180
174
  data={ data }
181
175
  actions={ actions }
182
176
  selection={ _selection }
183
- onSelectionChange={ onSetSelection }
177
+ onSelectionChange={ setSelectionWithChange }
184
178
  getItemId={ getItemId }
185
179
  />
186
180
  ) }
@@ -15,7 +15,7 @@ import {
15
15
  OPERATOR_IS_NOT_ALL,
16
16
  } from './constants';
17
17
  import { normalizeFields } from './normalize-fields';
18
- import type { Field, AnyItem, View } from './types';
18
+ import type { Field, View } from './types';
19
19
 
20
20
  function normalizeSearchInput( input = '' ) {
21
21
  return removeAccents( input.trim().toLowerCase() );
@@ -32,7 +32,7 @@ const EMPTY_ARRAY: [] = [];
32
32
  *
33
33
  * @return Filtered, sorted and paginated data.
34
34
  */
35
- export function filterSortAndPaginate< Item extends AnyItem >(
35
+ export function filterSortAndPaginate< Item >(
36
36
  data: Item[],
37
37
  view: View,
38
38
  fields: Field< Item >[]
@@ -61,7 +61,7 @@ export function filterSortAndPaginate< Item extends AnyItem >(
61
61
  } );
62
62
  }
63
63
 
64
- if ( view.filters.length > 0 ) {
64
+ if ( view.filters && view.filters?.length > 0 ) {
65
65
  view.filters.forEach( ( filter ) => {
66
66
  const field = _fields.find(
67
67
  ( _field ) => _field.id === filter.field
@@ -142,6 +142,16 @@ export function filterSortAndPaginate< Item extends AnyItem >(
142
142
  filteredData.sort( ( a, b ) => {
143
143
  const valueA = fieldToSort.getValue( { item: a } ) ?? '';
144
144
  const valueB = fieldToSort.getValue( { item: b } ) ?? '';
145
+
146
+ if (
147
+ typeof valueA === 'number' &&
148
+ typeof valueB === 'number'
149
+ ) {
150
+ return view.sort?.direction === 'asc'
151
+ ? valueA - valueB
152
+ : valueB - valueA;
153
+ }
154
+
145
155
  return view.sort?.direction === 'asc'
146
156
  ? valueA.localeCompare( valueB )
147
157
  : valueB.localeCompare( valueA );
@@ -157,7 +157,7 @@ function OperatorSelector( {
157
157
  value: operator,
158
158
  label: OPERATORS[ operator ]?.label,
159
159
  } ) );
160
- const currentFilter = view.filters.find(
160
+ const currentFilter = view.filters?.find(
161
161
  ( _filter ) => _filter.field === filter.field
162
162
  );
163
163
  const value = currentFilter?.operator || filter.operators[ 0 ];
@@ -180,18 +180,22 @@ function OperatorSelector( {
180
180
  const operator = newValue as Operator;
181
181
  const newFilters = currentFilter
182
182
  ? [
183
- ...view.filters.map( ( _filter ) => {
184
- if ( _filter.field === filter.field ) {
185
- return {
186
- ..._filter,
187
- operator,
188
- };
183
+ ...( view.filters ?? [] ).map(
184
+ ( _filter ) => {
185
+ if (
186
+ _filter.field === filter.field
187
+ ) {
188
+ return {
189
+ ..._filter,
190
+ operator,
191
+ };
192
+ }
193
+ return _filter;
189
194
  }
190
- return _filter;
191
- } ),
195
+ ),
192
196
  ]
193
197
  : [
194
- ...view.filters,
198
+ ...( view.filters ?? [] ),
195
199
  {
196
200
  field: filter.field,
197
201
  operator,
@@ -220,7 +224,9 @@ export default function FilterSummary( {
220
224
  }: FilterSummaryProps ) {
221
225
  const toggleRef = useRef< HTMLDivElement >( null );
222
226
  const { filter, view, onChangeView } = commonProps;
223
- const filterInView = view.filters.find( ( f ) => f.field === filter.field );
227
+ const filterInView = view.filters?.find(
228
+ ( f ) => f.field === filter.field
229
+ );
224
230
  const activeElements = filter.elements.filter( ( element ) => {
225
231
  if ( filter.singleSelection ) {
226
232
  return element.value === filterInView?.value;
@@ -290,7 +296,7 @@ export default function FilterSummary( {
290
296
  onChangeView( {
291
297
  ...view,
292
298
  page: 1,
293
- filters: view.filters.filter(
299
+ filters: view.filters?.filter(
294
300
  ( _filter ) =>
295
301
  _filter.field !== filter.field
296
302
  ),
package/src/filters.tsx CHANGED
@@ -12,9 +12,9 @@ import AddFilter from './add-filter';
12
12
  import ResetFilters from './reset-filters';
13
13
  import { sanitizeOperators } from './utils';
14
14
  import { ALL_OPERATORS, OPERATOR_IS, OPERATOR_IS_NOT } from './constants';
15
- import type { AnyItem, NormalizedField, NormalizedFilter, View } from './types';
15
+ import type { NormalizedField, NormalizedFilter, View } from './types';
16
16
 
17
- interface FiltersProps< Item extends AnyItem > {
17
+ interface FiltersProps< Item > {
18
18
  fields: NormalizedField< Item >[];
19
19
  view: View;
20
20
  onChangeView: ( view: View ) => void;
@@ -22,7 +22,7 @@ interface FiltersProps< Item extends AnyItem > {
22
22
  setOpenedFilter: ( openedFilter: string | null ) => void;
23
23
  }
24
24
 
25
- function _Filters< Item extends AnyItem >( {
25
+ function _Filters< Item >( {
26
26
  fields,
27
27
  view,
28
28
  onChangeView,
@@ -52,7 +52,7 @@ function _Filters< Item extends AnyItem >( {
52
52
  operators,
53
53
  isVisible:
54
54
  isPrimary ||
55
- view.filters.some(
55
+ !! view.filters?.some(
56
56
  ( f ) =>
57
57
  f.field === field.id &&
58
58
  ALL_OPERATORS.includes( f.operator )
package/src/index.ts CHANGED
@@ -2,3 +2,4 @@ export { default as DataViews } from './dataviews';
2
2
  export { VIEW_LAYOUTS } from './layouts';
3
3
  export { filterSortAndPaginate } from './filter-and-sort-data-view';
4
4
  export type * from './types';
5
+ export { default as DataForm } from './dataform';
@@ -21,7 +21,7 @@ import { useRegistry } from '@wordpress/data';
21
21
  * Internal dependencies
22
22
  */
23
23
  import { unlock } from './lock-unlock';
24
- import type { Action, ActionModal as ActionModalType, AnyItem } from './types';
24
+ import type { Action, ActionModal as ActionModalType } from './types';
25
25
 
26
26
  const {
27
27
  DropdownMenuV2: DropdownMenu,
@@ -31,42 +31,41 @@ const {
31
31
  kebabCase,
32
32
  } = unlock( componentsPrivateApis );
33
33
 
34
- export interface ActionTriggerProps< Item extends AnyItem > {
34
+ export interface ActionTriggerProps< Item > {
35
35
  action: Action< Item >;
36
36
  onClick: MouseEventHandler;
37
37
  isBusy?: boolean;
38
38
  items: Item[];
39
39
  }
40
40
 
41
- interface ActionModalProps< Item extends AnyItem > {
41
+ interface ActionModalProps< Item > {
42
42
  action: ActionModalType< Item >;
43
43
  items: Item[];
44
44
  closeModal?: () => void;
45
45
  }
46
46
 
47
- interface ActionWithModalProps< Item extends AnyItem >
48
- extends ActionModalProps< Item > {
47
+ interface ActionWithModalProps< Item > extends ActionModalProps< Item > {
49
48
  ActionTrigger: ( props: ActionTriggerProps< Item > ) => ReactElement;
50
49
  isBusy?: boolean;
51
50
  }
52
51
 
53
- interface ActionsDropdownMenuGroupProps< Item extends AnyItem > {
52
+ interface ActionsDropdownMenuGroupProps< Item > {
54
53
  actions: Action< Item >[];
55
54
  item: Item;
56
55
  }
57
56
 
58
- interface ItemActionsProps< Item extends AnyItem > {
57
+ interface ItemActionsProps< Item > {
59
58
  item: Item;
60
59
  actions: Action< Item >[];
61
60
  isCompact?: boolean;
62
61
  }
63
62
 
64
- interface CompactItemActionsProps< Item extends AnyItem > {
63
+ interface CompactItemActionsProps< Item > {
65
64
  item: Item;
66
65
  actions: Action< Item >[];
67
66
  }
68
67
 
69
- function ButtonTrigger< Item extends AnyItem >( {
68
+ function ButtonTrigger< Item >( {
70
69
  action,
71
70
  onClick,
72
71
  items,
@@ -84,7 +83,7 @@ function ButtonTrigger< Item extends AnyItem >( {
84
83
  );
85
84
  }
86
85
 
87
- function DropdownMenuItemTrigger< Item extends AnyItem >( {
86
+ function DropdownMenuItemTrigger< Item >( {
88
87
  action,
89
88
  onClick,
90
89
  items,
@@ -101,7 +100,7 @@ function DropdownMenuItemTrigger< Item extends AnyItem >( {
101
100
  );
102
101
  }
103
102
 
104
- export function ActionModal< Item extends AnyItem >( {
103
+ export function ActionModal< Item >( {
105
104
  action,
106
105
  items,
107
106
  closeModal,
@@ -124,7 +123,7 @@ export function ActionModal< Item extends AnyItem >( {
124
123
  );
125
124
  }
126
125
 
127
- export function ActionWithModal< Item extends AnyItem >( {
126
+ export function ActionWithModal< Item >( {
128
127
  action,
129
128
  items,
130
129
  ActionTrigger,
@@ -153,7 +152,7 @@ export function ActionWithModal< Item extends AnyItem >( {
153
152
  );
154
153
  }
155
154
 
156
- export function ActionsDropdownMenuGroup< Item extends AnyItem >( {
155
+ export function ActionsDropdownMenuGroup< Item >( {
157
156
  actions,
158
157
  item,
159
158
  }: ActionsDropdownMenuGroupProps< Item > ) {
@@ -186,7 +185,7 @@ export function ActionsDropdownMenuGroup< Item extends AnyItem >( {
186
185
  );
187
186
  }
188
187
 
189
- export default function ItemActions< Item extends AnyItem >( {
188
+ export default function ItemActions< Item >( {
190
189
  item,
191
190
  actions,
192
191
  isCompact,
@@ -247,7 +246,7 @@ export default function ItemActions< Item extends AnyItem >( {
247
246
  );
248
247
  }
249
248
 
250
- function CompactItemActions< Item extends AnyItem >( {
249
+ function CompactItemActions< Item >( {
251
250
  item,
252
251
  actions,
253
252
  }: CompactItemActionsProps< Item > ) {
@@ -258,7 +257,7 @@ function CompactItemActions< Item extends AnyItem >( {
258
257
  size="compact"
259
258
  icon={ moreVertical }
260
259
  label={ __( 'Actions' ) }
261
- __experimentalIsFocusable
260
+ accessibleWhenDisabled
262
261
  disabled={ ! actions.length }
263
262
  className="dataviews-all-actions-button"
264
263
  />
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Internal dependencies
3
3
  */
4
- import type { Field, AnyItem, NormalizedField } from './types';
4
+ import type { Field, NormalizedField, ItemRecord } from './types';
5
5
 
6
6
  /**
7
7
  * Apply default values and normalize the fields config.
@@ -9,11 +9,13 @@ import type { Field, AnyItem, NormalizedField } from './types';
9
9
  * @param fields Fields config.
10
10
  * @return Normalized fields config.
11
11
  */
12
- export function normalizeFields< Item extends AnyItem >(
12
+ export function normalizeFields< Item >(
13
13
  fields: Field< Item >[]
14
14
  ): NormalizedField< Item >[] {
15
15
  return fields.map( ( field ) => {
16
- const getValue = field.getValue || ( ( { item } ) => item[ field.id ] );
16
+ const getValue =
17
+ field.getValue ||
18
+ ( ( { item }: { item: ItemRecord } ) => item[ field.id ] );
17
19
 
18
20
  return {
19
21
  ...field,
@@ -90,7 +90,7 @@ const Pagination = memo( function Pagination( {
90
90
  } )
91
91
  }
92
92
  disabled={ currentPage === 1 }
93
- __experimentalIsFocusable
93
+ accessibleWhenDisabled
94
94
  label={ __( 'Previous page' ) }
95
95
  icon={ chevronLeft }
96
96
  showTooltip
@@ -102,7 +102,7 @@ const Pagination = memo( function Pagination( {
102
102
  onChangeView( { ...view, page: currentPage + 1 } )
103
103
  }
104
104
  disabled={ currentPage >= totalPages }
105
- __experimentalIsFocusable
105
+ accessibleWhenDisabled
106
106
  label={ __( 'Next page' ) }
107
107
  icon={ chevronRight }
108
108
  showTooltip
@@ -0,0 +1,2 @@
1
+ export type SelectionOrUpdater = string[] | ( ( prev: string[] ) => string[] );
2
+ export type SetSelection = ( selection: SelectionOrUpdater ) => void;