@wordpress/dataviews 0.4.1 → 0.5.1

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 (77) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/README.md +1 -0
  3. package/build/add-filter.js +25 -108
  4. package/build/add-filter.js.map +1 -1
  5. package/build/constants.js +9 -18
  6. package/build/constants.js.map +1 -1
  7. package/build/dataviews.js +22 -16
  8. package/build/dataviews.js.map +1 -1
  9. package/build/dropdown-menu-helper.js +1 -2
  10. package/build/dropdown-menu-helper.js.map +1 -1
  11. package/build/filter-summary.js +146 -78
  12. package/build/filter-summary.js.map +1 -1
  13. package/build/filters.js +32 -18
  14. package/build/filters.js.map +1 -1
  15. package/build/pagination.js +1 -2
  16. package/build/pagination.js.map +1 -1
  17. package/build/reset-filters.js +4 -1
  18. package/build/reset-filters.js.map +1 -1
  19. package/build/search-widget.js +111 -0
  20. package/build/search-widget.js.map +1 -0
  21. package/build/search.js +2 -3
  22. package/build/search.js.map +1 -1
  23. package/build/single-selection-checkbox.js +54 -0
  24. package/build/single-selection-checkbox.js.map +1 -0
  25. package/build/utils.js +14 -1
  26. package/build/utils.js.map +1 -1
  27. package/build/view-actions.js +2 -3
  28. package/build/view-actions.js.map +1 -1
  29. package/build/view-grid.js +92 -22
  30. package/build/view-grid.js.map +1 -1
  31. package/build/view-list.js +2 -1
  32. package/build/view-list.js.map +1 -1
  33. package/build/view-table.js +43 -132
  34. package/build/view-table.js.map +1 -1
  35. package/build-module/add-filter.js +28 -111
  36. package/build-module/add-filter.js.map +1 -1
  37. package/build-module/dataviews.js +23 -17
  38. package/build-module/dataviews.js.map +1 -1
  39. package/build-module/filter-summary.js +147 -80
  40. package/build-module/filter-summary.js.map +1 -1
  41. package/build-module/filters.js +32 -17
  42. package/build-module/filters.js.map +1 -1
  43. package/build-module/reset-filters.js +4 -1
  44. package/build-module/reset-filters.js.map +1 -1
  45. package/build-module/search-widget.js +101 -0
  46. package/build-module/search-widget.js.map +1 -0
  47. package/build-module/search.js +1 -1
  48. package/build-module/search.js.map +1 -1
  49. package/build-module/single-selection-checkbox.js +47 -0
  50. package/build-module/single-selection-checkbox.js.map +1 -0
  51. package/build-module/utils.js +12 -0
  52. package/build-module/utils.js.map +1 -1
  53. package/build-module/view-actions.js +1 -1
  54. package/build-module/view-actions.js.map +1 -1
  55. package/build-module/view-grid.js +92 -22
  56. package/build-module/view-grid.js.map +1 -1
  57. package/build-module/view-list.js +2 -1
  58. package/build-module/view-list.js.map +1 -1
  59. package/build-module/view-table.js +43 -131
  60. package/build-module/view-table.js.map +1 -1
  61. package/build-style/style-rtl.css +248 -44
  62. package/build-style/style.css +248 -44
  63. package/package.json +12 -11
  64. package/src/add-filter.js +39 -230
  65. package/src/dataviews.js +31 -20
  66. package/src/filter-summary.js +190 -136
  67. package/src/filters.js +42 -29
  68. package/src/reset-filters.js +12 -2
  69. package/src/search-widget.js +128 -0
  70. package/src/search.js +1 -1
  71. package/src/single-selection-checkbox.js +59 -0
  72. package/src/style.scss +254 -44
  73. package/src/utils.js +15 -0
  74. package/src/view-actions.js +1 -2
  75. package/src/view-grid.js +127 -53
  76. package/src/view-list.js +5 -1
  77. package/src/view-table.js +57 -230
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/dataviews",
3
- "version": "0.4.1",
3
+ "version": "0.5.1",
4
4
  "description": "DataViews is a component that provides an API to render datasets using different types of layouts (table, grid, list, etc.).",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -27,16 +27,17 @@
27
27
  "types": "build-types",
28
28
  "sideEffects": false,
29
29
  "dependencies": {
30
+ "@ariakit/react": "^0.3.12",
30
31
  "@babel/runtime": "^7.16.0",
31
- "@wordpress/a11y": "^3.50.0",
32
- "@wordpress/components": "^25.16.0",
33
- "@wordpress/compose": "^6.27.0",
34
- "@wordpress/element": "^5.27.0",
35
- "@wordpress/i18n": "^4.50.0",
36
- "@wordpress/icons": "^9.41.0",
37
- "@wordpress/keycodes": "^3.50.0",
38
- "@wordpress/primitives": "^3.48.0",
39
- "@wordpress/private-apis": "^0.32.0",
32
+ "@wordpress/a11y": "^3.51.0",
33
+ "@wordpress/components": "^26.0.1",
34
+ "@wordpress/compose": "^6.28.0",
35
+ "@wordpress/element": "^5.28.0",
36
+ "@wordpress/i18n": "^4.51.0",
37
+ "@wordpress/icons": "^9.42.0",
38
+ "@wordpress/keycodes": "^3.51.0",
39
+ "@wordpress/primitives": "^3.49.0",
40
+ "@wordpress/private-apis": "^0.33.0",
40
41
  "classnames": "^2.3.1",
41
42
  "remove-accents": "^0.5.0"
42
43
  },
@@ -46,5 +47,5 @@
46
47
  "publishConfig": {
47
48
  "access": "public"
48
49
  },
49
- "gitHead": "fefb6f718fbfd5df9390f366d5733369f613084a"
50
+ "gitHead": "5902fc0f490528da6965dd4cf97f11192bcf5956"
50
51
  }
package/src/add-filter.js CHANGED
@@ -5,261 +5,70 @@ import {
5
5
  privateApis as componentsPrivateApis,
6
6
  Button,
7
7
  } from '@wordpress/components';
8
- import { funnel } from '@wordpress/icons';
9
- import { __, sprintf } from '@wordpress/i18n';
10
- import { Children, Fragment } from '@wordpress/element';
8
+ import { plus } from '@wordpress/icons';
9
+ import { __ } from '@wordpress/i18n';
10
+ import { forwardRef } from '@wordpress/element';
11
11
 
12
12
  /**
13
13
  * Internal dependencies
14
14
  */
15
15
  import { unlock } from './lock-unlock';
16
- import { LAYOUT_LIST, OPERATORS } from './constants';
17
- import { DropdownMenuRadioItemCustom } from './dropdown-menu-helper';
18
16
 
19
17
  const {
20
18
  DropdownMenuV2: DropdownMenu,
21
- DropdownMenuGroupV2: DropdownMenuGroup,
22
19
  DropdownMenuItemV2: DropdownMenuItem,
23
- DropdownMenuRadioItemV2: DropdownMenuRadioItem,
24
- DropdownMenuSeparatorV2: DropdownMenuSeparator,
25
20
  DropdownMenuItemLabelV2: DropdownMenuItemLabel,
26
- DropdownMenuItemHelpTextV2: DropdownMenuItemHelpText,
27
21
  } = unlock( componentsPrivateApis );
28
22
 
29
- function WithSeparators( { children } ) {
30
- return Children.toArray( children )
31
- .filter( Boolean )
32
- .map( ( child, i ) => (
33
- <Fragment key={ i }>
34
- { i > 0 && <DropdownMenuSeparator /> }
35
- { child }
36
- </Fragment>
37
- ) );
38
- }
39
-
40
- export default function AddFilter( { filters, view, onChangeView } ) {
41
- if ( filters.length === 0 ) {
23
+ function AddFilter( { filters, view, onChangeView, setOpenedFilter }, ref ) {
24
+ if ( ! filters.length || filters.every( ( { isPrimary } ) => isPrimary ) ) {
42
25
  return null;
43
26
  }
44
-
45
- const filterCount = view.filters.reduce( ( acc, filter ) => {
46
- if ( filter.value !== undefined ) {
47
- return acc + 1;
48
- }
49
- return acc;
50
- }, 0 );
51
-
27
+ const inactiveFilters = filters.filter( ( filter ) => ! filter.isVisible );
52
28
  return (
53
29
  <DropdownMenu
54
30
  trigger={
55
31
  <Button
56
32
  __experimentalIsFocusable
57
- label={ __( 'Filters' ) }
58
33
  size="compact"
59
- icon={ funnel }
34
+ icon={ plus }
60
35
  className="dataviews-filters-button"
36
+ variant="tertiary"
37
+ disabled={ ! inactiveFilters.length }
38
+ ref={ ref }
61
39
  >
62
- { view.type === LAYOUT_LIST && filterCount > 0 ? (
63
- <span className="dataviews-filters-count">
64
- { filterCount }
65
- </span>
66
- ) : null }
40
+ { __( 'Add filter' ) }
67
41
  </Button>
68
42
  }
69
- style={ {
70
- minWidth: '230px',
71
- } }
72
43
  >
73
- <WithSeparators>
74
- <DropdownMenuGroup>
75
- { filters.map( ( filter ) => {
76
- const filterInView = view.filters.find(
77
- ( f ) => f.field === filter.field
78
- );
79
- const otherFilters = view.filters.filter(
80
- ( f ) => f.field !== filter.field
81
- );
82
- const activeElement = filter.elements.find(
83
- ( element ) => element.value === filterInView?.value
84
- );
85
- const activeOperator =
86
- filterInView?.operator || filter.operators[ 0 ];
87
- return (
88
- <DropdownMenu
89
- key={ filter.field }
90
- trigger={
91
- <DropdownMenuItem
92
- suffix={
93
- activeElement && (
94
- <span aria-hidden="true">
95
- { activeOperator in
96
- OPERATORS &&
97
- `${ OPERATORS[ activeOperator ].label } ` }
98
- { activeElement.label }
99
- </span>
100
- )
101
- }
102
- >
103
- <DropdownMenuItemLabel>
104
- { filter.name }
105
- </DropdownMenuItemLabel>
106
- </DropdownMenuItem>
107
- }
108
- style={ {
109
- minWidth: '200px',
110
- } }
111
- >
112
- <WithSeparators>
113
- <DropdownMenuGroup>
114
- { filter.elements.map( ( element ) => {
115
- const isActive =
116
- activeElement?.value ===
117
- element.value;
118
- return (
119
- <DropdownMenuRadioItemCustom
120
- key={ element.value }
121
- name={ `add-filter-${ filter.field }` }
122
- value={ element.value }
123
- checked={ isActive }
124
- onChange={ ( e ) => {
125
- onChangeView( {
126
- ...view,
127
- page: 1,
128
- filters: [
129
- ...otherFilters,
130
- {
131
- field: filter.field,
132
- operator:
133
- activeOperator,
134
- value: isActive
135
- ? undefined
136
- : e
137
- .target
138
- .value,
139
- },
140
- ],
141
- } );
142
- } }
143
- >
144
- <DropdownMenuItemLabel>
145
- { element.label }
146
- </DropdownMenuItemLabel>
147
- { !! element.description && (
148
- <DropdownMenuItemHelpText>
149
- {
150
- element.description
151
- }
152
- </DropdownMenuItemHelpText>
153
- ) }
154
- </DropdownMenuRadioItemCustom>
155
- );
156
- } ) }
157
- </DropdownMenuGroup>
158
- { filter.operators.length > 1 && (
159
- <DropdownMenu
160
- trigger={
161
- <DropdownMenuItem
162
- suffix={
163
- <span aria-hidden="true">
164
- {
165
- OPERATORS[
166
- activeOperator
167
- ]?.label
168
- }
169
- </span>
170
- }
171
- >
172
- <DropdownMenuItemLabel>
173
- { __( 'Conditions' ) }
174
- </DropdownMenuItemLabel>
175
- </DropdownMenuItem>
176
- }
177
- >
178
- { Object.entries( OPERATORS ).map(
179
- ( [
180
- operator,
181
- { label, key },
182
- ] ) => (
183
- <DropdownMenuRadioItem
184
- key={ key }
185
- name={ `add-filter-${ filter.field }-conditions` }
186
- value={ operator }
187
- checked={
188
- activeOperator ===
189
- operator
190
- }
191
- onChange={ ( e ) => {
192
- onChangeView( {
193
- ...view,
194
- page: 1,
195
- filters: [
196
- ...otherFilters,
197
- {
198
- field: filter.field,
199
- operator:
200
- e
201
- .target
202
- .value,
203
- value: filterInView?.value,
204
- },
205
- ],
206
- } );
207
- } }
208
- >
209
- <DropdownMenuItemLabel>
210
- { label }
211
- </DropdownMenuItemLabel>
212
- </DropdownMenuRadioItem>
213
- )
214
- ) }
215
- </DropdownMenu>
216
- ) }
217
- <DropdownMenuItem
218
- key={ 'reset-filter-' + filter.name }
219
- disabled={ ! activeElement }
220
- hideOnClick={ false }
221
- onClick={ () => {
222
- onChangeView( {
223
- ...view,
224
- page: 1,
225
- filters: view.filters.filter(
226
- ( f ) =>
227
- f.field !== filter.field
228
- ),
229
- } );
230
- } }
231
- >
232
- <DropdownMenuItemLabel>
233
- { sprintf(
234
- /* translators: 1: Filter name. e.g.: "Reset Author". */
235
- __( 'Reset %1$s' ),
236
- filter.name.toLowerCase()
237
- ) }
238
- </DropdownMenuItemLabel>
239
- </DropdownMenuItem>
240
- </WithSeparators>
241
- </DropdownMenu>
242
- );
243
- } ) }
244
- </DropdownMenuGroup>
245
- <DropdownMenuItem
246
- disabled={
247
- view.search === '' && view.filters?.length === 0
248
- }
249
- hideOnClick={ false }
250
- onClick={ () => {
251
- onChangeView( {
252
- ...view,
253
- page: 1,
254
- filters: [],
255
- } );
256
- } }
257
- >
258
- <DropdownMenuItemLabel>
259
- { __( 'Reset filters' ) }
260
- </DropdownMenuItemLabel>
261
- </DropdownMenuItem>
262
- </WithSeparators>
44
+ { inactiveFilters.map( ( filter ) => {
45
+ return (
46
+ <DropdownMenuItem
47
+ key={ filter.field }
48
+ onClick={ () => {
49
+ setOpenedFilter( filter.field );
50
+ onChangeView( {
51
+ ...view,
52
+ page: 1,
53
+ filters: [
54
+ ...( view.filters || [] ),
55
+ {
56
+ field: filter.field,
57
+ value: undefined,
58
+ operator: filter.operators[ 0 ],
59
+ },
60
+ ],
61
+ } );
62
+ } }
63
+ >
64
+ <DropdownMenuItemLabel>
65
+ { filter.name }
66
+ </DropdownMenuItemLabel>
67
+ </DropdownMenuItem>
68
+ );
69
+ } ) }
263
70
  </DropdownMenu>
264
71
  );
265
72
  }
73
+
74
+ export default forwardRef( AddFilter );
package/src/dataviews.js CHANGED
@@ -14,7 +14,7 @@ import Pagination from './pagination';
14
14
  import ViewActions from './view-actions';
15
15
  import Filters from './filters';
16
16
  import Search from './search';
17
- import { VIEW_LAYOUTS, LAYOUT_TABLE } from './constants';
17
+ import { VIEW_LAYOUTS, LAYOUT_TABLE, LAYOUT_GRID } from './constants';
18
18
  import BulkActions from './bulk-actions';
19
19
 
20
20
  const defaultGetItemId = ( item ) => item.id;
@@ -37,30 +37,33 @@ export default function DataViews( {
37
37
  deferredRendering = false,
38
38
  } ) {
39
39
  const [ selection, setSelection ] = useState( [] );
40
+ const [ openedFilter, setOpenedFilter ] = useState( null );
40
41
 
41
42
  useEffect( () => {
42
43
  if (
43
44
  selection.length > 0 &&
44
45
  selection.some(
45
- ( id ) => ! data.some( ( item ) => item.id === id )
46
+ ( id ) => ! data.some( ( item ) => getItemId( item ) === id )
46
47
  )
47
48
  ) {
48
49
  const newSelection = selection.filter( ( id ) =>
49
- data.some( ( item ) => item.id === id )
50
+ data.some( ( item ) => getItemId( item ) === id )
50
51
  );
51
52
  setSelection( newSelection );
52
53
  onSelectionChange(
53
- data.filter( ( item ) => newSelection.includes( item.id ) )
54
+ data.filter( ( item ) =>
55
+ newSelection.includes( getItemId( item ) )
56
+ )
54
57
  );
55
58
  }
56
- }, [ selection, data, onSelectionChange ] );
59
+ }, [ selection, data, getItemId, onSelectionChange ] );
57
60
 
58
61
  const onSetSelection = useCallback(
59
62
  ( items ) => {
60
- setSelection( items.map( ( item ) => item.id ) );
63
+ setSelection( items.map( ( item ) => getItemId( item ) ) );
61
64
  onSelectionChange( items );
62
65
  },
63
- [ setSelection, onSelectionChange ]
66
+ [ setSelection, getItemId, onSelectionChange ]
64
67
  );
65
68
 
66
69
  const ViewComponent = VIEW_LAYOUTS.find(
@@ -74,26 +77,20 @@ export default function DataViews( {
74
77
  }, [ fields ] );
75
78
  return (
76
79
  <div className="dataviews-wrapper">
77
- <VStack spacing={ 0 } justify="flex-start">
80
+ <VStack spacing={ 3 } justify="flex-start">
78
81
  <HStack
79
82
  alignment="flex-start"
83
+ justify="start"
80
84
  className="dataviews-filters__view-actions"
81
85
  >
82
- <HStack justify="start" wrap>
83
- { search && (
84
- <Search
85
- label={ searchLabel }
86
- view={ view }
87
- onChangeView={ onChangeView }
88
- />
89
- ) }
90
- <Filters
91
- fields={ _fields }
86
+ { search && (
87
+ <Search
88
+ label={ searchLabel }
92
89
  view={ view }
93
90
  onChangeView={ onChangeView }
94
91
  />
95
- </HStack>
96
- { view.type === LAYOUT_TABLE && (
92
+ ) }
93
+ { [ LAYOUT_TABLE, LAYOUT_GRID ].includes( view.type ) && (
97
94
  <BulkActions
98
95
  actions={ actions }
99
96
  data={ data }
@@ -109,6 +106,19 @@ export default function DataViews( {
109
106
  supportedLayouts={ supportedLayouts }
110
107
  />
111
108
  </HStack>
109
+ <HStack
110
+ justify="start"
111
+ className="dataviews-filters__container"
112
+ wrap
113
+ >
114
+ <Filters
115
+ fields={ _fields }
116
+ view={ view }
117
+ onChangeView={ onChangeView }
118
+ openedFilter={ openedFilter }
119
+ setOpenedFilter={ setOpenedFilter }
120
+ />
121
+ </HStack>
112
122
  <ViewComponent
113
123
  fields={ _fields }
114
124
  view={ view }
@@ -121,6 +131,7 @@ export default function DataViews( {
121
131
  onDetailsChange={ onDetailsChange }
122
132
  selection={ selection }
123
133
  deferredRendering={ deferredRendering }
134
+ setOpenedFilter={ setOpenedFilter }
124
135
  />
125
136
  <Pagination
126
137
  view={ view }