@wordpress/dataviews 9.0.1-next.a730c9c8c.0 → 9.1.1-next.233ccab9b.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 (100) hide show
  1. package/CHANGELOG.md +19 -3
  2. package/README.md +4 -2
  3. package/build/components/dataviews/index.js +4 -6
  4. package/build/components/dataviews/index.js.map +1 -1
  5. package/build/components/dataviews-filters/filters-toggled.js +32 -0
  6. package/build/components/dataviews-filters/filters-toggled.js.map +1 -0
  7. package/build/components/dataviews-filters/filters.js +73 -0
  8. package/build/components/dataviews-filters/filters.js.map +1 -0
  9. package/build/components/dataviews-filters/index.js +26 -190
  10. package/build/components/dataviews-filters/index.js.map +1 -1
  11. package/build/components/dataviews-filters/toggle.js +99 -0
  12. package/build/components/dataviews-filters/toggle.js.map +1 -0
  13. package/build/components/dataviews-filters/use-filters.js +63 -0
  14. package/build/components/dataviews-filters/use-filters.js.map +1 -0
  15. package/build/components/dataviews-picker/index.js +4 -6
  16. package/build/components/dataviews-picker/index.js.map +1 -1
  17. package/build/components/dataviews-view-config/index.js +22 -3
  18. package/build/components/dataviews-view-config/index.js.map +1 -1
  19. package/build/dataform-controls/array.js +110 -24
  20. package/build/dataform-controls/array.js.map +1 -1
  21. package/build/dataviews-layouts/picker-grid/index.js +4 -1
  22. package/build/dataviews-layouts/picker-grid/index.js.map +1 -1
  23. package/build/field-types/array.js +0 -6
  24. package/build/field-types/array.js.map +1 -1
  25. package/build/index.js +7 -0
  26. package/build/index.js.map +1 -1
  27. package/build/types.js.map +1 -1
  28. package/build/validation.js +18 -1
  29. package/build/validation.js.map +1 -1
  30. package/build-module/components/dataviews/index.js +5 -7
  31. package/build-module/components/dataviews/index.js.map +1 -1
  32. package/build-module/components/dataviews-filters/filters-toggled.js +24 -0
  33. package/build-module/components/dataviews-filters/filters-toggled.js.map +1 -0
  34. package/build-module/components/dataviews-filters/filters.js +65 -0
  35. package/build-module/components/dataviews-filters/filters.js.map +1 -0
  36. package/build-module/components/dataviews-filters/index.js +4 -186
  37. package/build-module/components/dataviews-filters/index.js.map +1 -1
  38. package/build-module/components/dataviews-filters/toggle.js +91 -0
  39. package/build-module/components/dataviews-filters/toggle.js.map +1 -0
  40. package/build-module/components/dataviews-filters/use-filters.js +56 -0
  41. package/build-module/components/dataviews-filters/use-filters.js.map +1 -0
  42. package/build-module/components/dataviews-picker/index.js +5 -7
  43. package/build-module/components/dataviews-picker/index.js.map +1 -1
  44. package/build-module/components/dataviews-view-config/index.js +22 -3
  45. package/build-module/components/dataviews-view-config/index.js.map +1 -1
  46. package/build-module/dataform-controls/array.js +112 -26
  47. package/build-module/dataform-controls/array.js.map +1 -1
  48. package/build-module/dataviews-layouts/picker-grid/index.js +4 -1
  49. package/build-module/dataviews-layouts/picker-grid/index.js.map +1 -1
  50. package/build-module/field-types/array.js +0 -6
  51. package/build-module/field-types/array.js.map +1 -1
  52. package/build-module/index.js +1 -0
  53. package/build-module/index.js.map +1 -1
  54. package/build-module/types.js.map +1 -1
  55. package/build-module/validation.js +18 -1
  56. package/build-module/validation.js.map +1 -1
  57. package/build-types/components/dataform/stories/index.story.d.ts.map +1 -1
  58. package/build-types/components/dataviews/index.d.ts +3 -2
  59. package/build-types/components/dataviews/index.d.ts.map +1 -1
  60. package/build-types/components/dataviews-filters/filters-toggled.d.ts +5 -0
  61. package/build-types/components/dataviews-filters/filters-toggled.d.ts.map +1 -0
  62. package/build-types/components/dataviews-filters/filters.d.ts +6 -0
  63. package/build-types/components/dataviews-filters/filters.d.ts.map +1 -0
  64. package/build-types/components/dataviews-filters/index.d.ts +4 -8
  65. package/build-types/components/dataviews-filters/index.d.ts.map +1 -1
  66. package/build-types/components/dataviews-filters/toggle.d.ts +3 -0
  67. package/build-types/components/dataviews-filters/toggle.d.ts.map +1 -0
  68. package/build-types/components/dataviews-filters/use-filters.d.ts +4 -0
  69. package/build-types/components/dataviews-filters/use-filters.d.ts.map +1 -0
  70. package/build-types/components/dataviews-picker/index.d.ts +3 -2
  71. package/build-types/components/dataviews-picker/index.d.ts.map +1 -1
  72. package/build-types/components/dataviews-view-config/index.d.ts.map +1 -1
  73. package/build-types/dataform-controls/array.d.ts.map +1 -1
  74. package/build-types/dataviews-layouts/picker-grid/index.d.ts.map +1 -1
  75. package/build-types/field-types/array.d.ts.map +1 -1
  76. package/build-types/index.d.ts +1 -0
  77. package/build-types/index.d.ts.map +1 -1
  78. package/build-types/types.d.ts +2 -1
  79. package/build-types/types.d.ts.map +1 -1
  80. package/build-types/validation.d.ts.map +1 -1
  81. package/build-wp/index.js +899 -408
  82. package/package.json +15 -15
  83. package/src/components/dataform/stories/index.story.tsx +73 -1
  84. package/src/components/dataviews/index.tsx +8 -14
  85. package/src/components/dataviews/stories/index.story.tsx +1 -1
  86. package/src/components/dataviews-filters/filters-toggled.tsx +20 -0
  87. package/src/components/dataviews-filters/filters.tsx +73 -0
  88. package/src/components/dataviews-filters/index.tsx +4 -246
  89. package/src/components/dataviews-filters/toggle.tsx +118 -0
  90. package/src/components/dataviews-filters/use-filters.ts +73 -0
  91. package/src/components/dataviews-picker/index.tsx +8 -14
  92. package/src/components/dataviews-view-config/index.tsx +18 -3
  93. package/src/dataform-controls/array.tsx +137 -40
  94. package/src/dataviews-layouts/picker-grid/index.tsx +15 -8
  95. package/src/field-types/array.tsx +0 -8
  96. package/src/index.ts +1 -0
  97. package/src/test/validation.ts +192 -0
  98. package/src/types.ts +2 -1
  99. package/src/validation.ts +30 -0
  100. package/tsconfig.tsbuildinfo +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/dataviews",
3
- "version": "9.0.1-next.a730c9c8c.0",
3
+ "version": "9.1.1-next.233ccab9b.0",
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",
@@ -46,19 +46,19 @@
46
46
  "dependencies": {
47
47
  "@ariakit/react": "^0.4.15",
48
48
  "@babel/runtime": "7.25.7",
49
- "@wordpress/base-styles": "^6.6.1-next.a730c9c8c.0",
50
- "@wordpress/components": "^30.3.2-next.a730c9c8c.0",
51
- "@wordpress/compose": "^7.30.1-next.a730c9c8c.0",
52
- "@wordpress/data": "^10.30.1-next.a730c9c8c.0",
53
- "@wordpress/date": "^5.30.1-next.a730c9c8c.0",
54
- "@wordpress/element": "^6.30.1-next.a730c9c8c.0",
55
- "@wordpress/i18n": "^6.3.1-next.a730c9c8c.0",
56
- "@wordpress/icons": "^10.30.1-next.a730c9c8c.0",
57
- "@wordpress/keycodes": "^4.30.1-next.a730c9c8c.0",
58
- "@wordpress/primitives": "^4.30.1-next.a730c9c8c.0",
59
- "@wordpress/private-apis": "^1.30.1-next.a730c9c8c.0",
60
- "@wordpress/url": "^4.30.1-next.a730c9c8c.0",
61
- "@wordpress/warning": "^3.30.1-next.a730c9c8c.0",
49
+ "@wordpress/base-styles": "^6.7.1-next.233ccab9b.0",
50
+ "@wordpress/components": "^30.5.1-next.233ccab9b.0",
51
+ "@wordpress/compose": "^7.31.1-next.233ccab9b.0",
52
+ "@wordpress/data": "^10.31.1-next.233ccab9b.0",
53
+ "@wordpress/date": "^5.31.1-next.233ccab9b.0",
54
+ "@wordpress/element": "^6.31.1-next.233ccab9b.0",
55
+ "@wordpress/i18n": "^6.4.1-next.233ccab9b.0",
56
+ "@wordpress/icons": "^10.31.1-next.233ccab9b.0",
57
+ "@wordpress/keycodes": "^4.31.1-next.233ccab9b.0",
58
+ "@wordpress/primitives": "^4.31.1-next.233ccab9b.0",
59
+ "@wordpress/private-apis": "^1.31.1-next.233ccab9b.0",
60
+ "@wordpress/url": "^4.31.1-next.233ccab9b.0",
61
+ "@wordpress/warning": "^3.31.1-next.233ccab9b.0",
62
62
  "clsx": "^2.1.1",
63
63
  "colord": "^2.7.0",
64
64
  "date-fns": "^4.1.0",
@@ -76,5 +76,5 @@
76
76
  "scripts": {
77
77
  "build:wp": "node build"
78
78
  },
79
- "gitHead": "85a580bd2c55f811c8969b42dbb10209d19d514e"
79
+ "gitHead": "d11f971521e4b39b07124d5c5516890ff98b0e31"
80
80
  }
@@ -525,6 +525,8 @@ const ValidationComponent = ( {
525
525
  integer: number;
526
526
  boolean: boolean;
527
527
  customEdit: string;
528
+ categories: string[];
529
+ countries: string[];
528
530
  password: string;
529
531
  toggle?: boolean;
530
532
  toggleGroup?: string;
@@ -541,6 +543,8 @@ const ValidationComponent = ( {
541
543
  color: '#ff6600',
542
544
  integer: 2,
543
545
  boolean: true,
546
+ categories: [ 'astronomy' ],
547
+ countries: [ 'us' ],
544
548
  customEdit: 'custom control',
545
549
  password: 'secretpassword123',
546
550
  toggle: undefined,
@@ -755,6 +759,41 @@ const ValidationComponent = ( {
755
759
  custom: maybeCustomRule( customBooleanRule ),
756
760
  },
757
761
  },
762
+ {
763
+ id: 'categories',
764
+ type: 'array' as const,
765
+ label: 'Categories',
766
+ isValid: {
767
+ required,
768
+ },
769
+ elements: [
770
+ { value: 'astronomy', label: 'Astronomy' },
771
+ { value: 'book-review', label: 'Book review' },
772
+ { value: 'event', label: 'Event' },
773
+ { value: 'photography', label: 'Photography' },
774
+ { value: 'travel', label: 'Travel' },
775
+ ],
776
+ },
777
+ {
778
+ id: 'countries',
779
+ label: 'Countries Visited',
780
+ type: 'array' as const,
781
+ placeholder: 'Select countries',
782
+ description: 'Countries you have visited',
783
+ isValid: {
784
+ required,
785
+ elements: true,
786
+ },
787
+ elements: [
788
+ { value: 'us', label: 'United States' },
789
+ { value: 'ca', label: 'Canada' },
790
+ { value: 'uk', label: 'United Kingdom' },
791
+ { value: 'fr', label: 'France' },
792
+ { value: 'de', label: 'Germany' },
793
+ { value: 'jp', label: 'Japan' },
794
+ { value: 'au', label: 'Australia' },
795
+ ],
796
+ },
758
797
  {
759
798
  id: 'customEdit',
760
799
  label: 'Custom Control',
@@ -812,6 +851,8 @@ const ValidationComponent = ( {
812
851
  'color',
813
852
  'integer',
814
853
  'boolean',
854
+ 'categories',
855
+ 'countries',
815
856
  'toggle',
816
857
  'toggleGroup',
817
858
  'password',
@@ -853,11 +894,15 @@ const VisibilityComponent = () => {
853
894
  name: string;
854
895
  email: string;
855
896
  isActive: boolean;
897
+ homepageDisplay: string;
898
+ staticHomepage: string;
856
899
  };
857
900
  const [ data, setData ] = useState( {
858
901
  name: '',
859
902
  email: '',
860
903
  isActive: true,
904
+ homepageDisplay: 'latest',
905
+ staticHomepage: '',
861
906
  } );
862
907
 
863
908
  const _fields: Field< Post >[] = [
@@ -874,9 +919,36 @@ const VisibilityComponent = () => {
874
919
  type: 'email',
875
920
  isVisible: ( post ) => post.isActive === true,
876
921
  },
922
+ {
923
+ id: 'homepageDisplay',
924
+ label: 'Homepage display',
925
+ elements: [
926
+ { value: 'latest', label: 'Latest post' },
927
+ { value: 'static', label: 'Static page' },
928
+ ],
929
+ },
930
+ {
931
+ id: 'staticHomepage',
932
+ label: 'Static homepage',
933
+ elements: [
934
+ { value: 'welcome', label: 'Welcome to my website' },
935
+ { value: 'about', label: 'About' },
936
+ ],
937
+ isVisible: ( post ) => post.homepageDisplay === 'static',
938
+ },
877
939
  ];
878
940
  const form: Form = {
879
- fields: [ 'isActive', 'name', 'email' ],
941
+ layout: { type: 'card' },
942
+ fields: [
943
+ {
944
+ id: 'booleanExample',
945
+ children: [ 'isActive', 'name', 'email' ],
946
+ },
947
+ {
948
+ id: 'selectExample',
949
+ children: [ 'homepageDisplay', 'staticHomepage' ],
950
+ },
951
+ ],
880
952
  };
881
953
  return (
882
954
  <DataForm< Post >
@@ -7,13 +7,7 @@ import type { ReactNode, ComponentProps, ReactElement } from 'react';
7
7
  * WordPress dependencies
8
8
  */
9
9
  import { __experimentalHStack as HStack } from '@wordpress/components';
10
- import {
11
- useContext,
12
- useEffect,
13
- useMemo,
14
- useRef,
15
- useState,
16
- } from '@wordpress/element';
10
+ import { useEffect, useMemo, useRef, useState } from '@wordpress/element';
17
11
  import { useResizeObserver, throttle } from '@wordpress/compose';
18
12
 
19
13
  /**
@@ -22,7 +16,8 @@ import { useResizeObserver, throttle } from '@wordpress/compose';
22
16
  import DataViewsContext from '../dataviews-context';
23
17
  import { VIEW_LAYOUTS } from '../../dataviews-layouts';
24
18
  import {
25
- default as DataViewsFilters,
19
+ Filters,
20
+ FiltersToggled,
26
21
  useFilters,
27
22
  FiltersToggle,
28
23
  } from '../dataviews-filters';
@@ -93,7 +88,6 @@ function DefaultUI( {
93
88
  search = true,
94
89
  searchLabel = undefined,
95
90
  }: DefaultUIProps ) {
96
- const { isShowingFilter } = useContext( DataViewsContext );
97
91
  return (
98
92
  <>
99
93
  <HStack
@@ -119,9 +113,7 @@ function DefaultUI( {
119
113
  { header }
120
114
  </HStack>
121
115
  </HStack>
122
- { isShowingFilter && (
123
- <DataViewsFilters className="dataviews-filters__container" />
124
- ) }
116
+ <FiltersToggled className="dataviews-filters__container" />
125
117
  <DataViewsLayout />
126
118
  <DataViewsFooter />
127
119
  </>
@@ -295,8 +287,9 @@ function DataViews< Item >( {
295
287
  // Populate the DataViews sub components
296
288
  const DataViewsSubComponents = DataViews as typeof DataViews & {
297
289
  BulkActionToolbar: typeof BulkActionsFooter;
298
- Filters: typeof DataViewsFilters;
290
+ Filters: typeof Filters;
299
291
  FiltersToggle: typeof FiltersToggle;
292
+ FiltersToggled: typeof FiltersToggled;
300
293
  Layout: typeof DataViewsLayout;
301
294
  LayoutSwitcher: typeof ViewTypeMenu;
302
295
  Pagination: typeof DataViewsPagination;
@@ -306,7 +299,8 @@ const DataViewsSubComponents = DataViews as typeof DataViews & {
306
299
  };
307
300
 
308
301
  DataViewsSubComponents.BulkActionToolbar = BulkActionsFooter;
309
- DataViewsSubComponents.Filters = DataViewsFilters;
302
+ DataViewsSubComponents.Filters = Filters;
303
+ DataViewsSubComponents.FiltersToggled = FiltersToggled;
310
304
  DataViewsSubComponents.FiltersToggle = FiltersToggle;
311
305
  DataViewsSubComponents.Layout = DataViewsLayout;
312
306
  DataViewsSubComponents.LayoutSwitcher = ViewTypeMenu;
@@ -273,7 +273,7 @@ function PlanetOverview( { planets }: { planets: SpaceObject[] } ) {
273
273
  <DataViews.FiltersToggle />
274
274
  <DataViews.Search label={ __( 'moons by planet' ) } />
275
275
  </HStack>
276
- <DataViews.Filters />
276
+ <DataViews.FiltersToggled />
277
277
  </VStack>
278
278
 
279
279
  <VStack>
@@ -0,0 +1,20 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useContext } from '@wordpress/element';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import DataViewsContext from '../dataviews-context';
10
+ import Filters from './filters';
11
+
12
+ function FiltersToggled( props: { className?: string } ) {
13
+ const { isShowingFilter } = useContext( DataViewsContext );
14
+ if ( ! isShowingFilter ) {
15
+ return null;
16
+ }
17
+ return <Filters { ...props } />;
18
+ }
19
+
20
+ export default FiltersToggled;
@@ -0,0 +1,73 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { memo, useContext, useRef } from '@wordpress/element';
5
+ import { __experimentalHStack as HStack } from '@wordpress/components';
6
+
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ import Filter from './filter';
11
+ import { default as AddFilter } from './add-filter';
12
+ import ResetFilters from './reset-filters';
13
+ import useFilters from './use-filters';
14
+ import DataViewsContext from '../dataviews-context';
15
+
16
+ function Filters( { className }: { className?: string } ) {
17
+ const { fields, view, onChangeView, openedFilter, setOpenedFilter } =
18
+ useContext( DataViewsContext );
19
+ const addFilterRef = useRef< HTMLButtonElement >( null );
20
+ const filters = useFilters( fields, view );
21
+ const addFilter = (
22
+ <AddFilter
23
+ key="add-filter"
24
+ filters={ filters }
25
+ view={ view }
26
+ onChangeView={ onChangeView }
27
+ ref={ addFilterRef }
28
+ setOpenedFilter={ setOpenedFilter }
29
+ />
30
+ );
31
+ const visibleFilters = filters.filter( ( filter ) => filter.isVisible );
32
+ if ( visibleFilters.length === 0 ) {
33
+ return null;
34
+ }
35
+ const filterComponents = [
36
+ ...visibleFilters.map( ( filter ) => {
37
+ return (
38
+ <Filter
39
+ key={ filter.field }
40
+ filter={ filter }
41
+ view={ view }
42
+ fields={ fields }
43
+ onChangeView={ onChangeView }
44
+ addFilterRef={ addFilterRef }
45
+ openedFilter={ openedFilter }
46
+ />
47
+ );
48
+ } ),
49
+ addFilter,
50
+ ];
51
+
52
+ filterComponents.push(
53
+ <ResetFilters
54
+ key="reset-filters"
55
+ filters={ filters }
56
+ view={ view }
57
+ onChangeView={ onChangeView }
58
+ />
59
+ );
60
+
61
+ return (
62
+ <HStack
63
+ justify="flex-start"
64
+ style={ { width: 'fit-content' } }
65
+ wrap
66
+ className={ className }
67
+ >
68
+ { filterComponents }
69
+ </HStack>
70
+ );
71
+ }
72
+
73
+ export default memo( Filters );
@@ -1,246 +1,4 @@
1
- /**
2
- * WordPress dependencies
3
- */
4
- import {
5
- memo,
6
- useContext,
7
- useRef,
8
- useMemo,
9
- useCallback,
10
- useEffect,
11
- } from '@wordpress/element';
12
- import { __experimentalHStack as HStack, Button } from '@wordpress/components';
13
- import { funnel } from '@wordpress/icons';
14
- import { __, _x } from '@wordpress/i18n';
15
-
16
- /**
17
- * Internal dependencies
18
- */
19
- import Filter from './filter';
20
- import { default as AddFilter, AddFilterMenu } from './add-filter';
21
- import ResetFilters from './reset-filters';
22
- import DataViewsContext from '../dataviews-context';
23
- import { ALL_OPERATORS, SINGLE_SELECTION_OPERATORS } from '../../constants';
24
- import type { NormalizedFilter, NormalizedField, View } from '../../types';
25
-
26
- export function useFilters( fields: NormalizedField< any >[], view: View ) {
27
- return useMemo( () => {
28
- const filters: NormalizedFilter[] = [];
29
- fields.forEach( ( field ) => {
30
- if (
31
- field.filterBy === false ||
32
- ( ! field.elements?.length && ! field.Edit )
33
- ) {
34
- return;
35
- }
36
-
37
- const operators = field.filterBy.operators;
38
- const isPrimary = !! field.filterBy?.isPrimary;
39
- const isLocked =
40
- view.filters?.some(
41
- ( f ) => f.field === field.id && !! f.isLocked
42
- ) ?? false;
43
- filters.push( {
44
- field: field.id,
45
- name: field.label,
46
- elements: field.elements ?? [],
47
- singleSelection: operators.some( ( op ) =>
48
- SINGLE_SELECTION_OPERATORS.includes( op )
49
- ),
50
- operators,
51
- isVisible:
52
- isLocked ||
53
- isPrimary ||
54
- !! view.filters?.some(
55
- ( f ) =>
56
- f.field === field.id &&
57
- ALL_OPERATORS.includes( f.operator )
58
- ),
59
- isPrimary,
60
- isLocked,
61
- } );
62
- } );
63
-
64
- // Sort filters by:
65
- // - locked filters go first
66
- // - primary filters go next
67
- // - then, sort by name
68
- filters.sort( ( a, b ) => {
69
- if ( a.isLocked && ! b.isLocked ) {
70
- return -1;
71
- }
72
- if ( ! a.isLocked && b.isLocked ) {
73
- return 1;
74
- }
75
- if ( a.isPrimary && ! b.isPrimary ) {
76
- return -1;
77
- }
78
- if ( ! a.isPrimary && b.isPrimary ) {
79
- return 1;
80
- }
81
- return a.name.localeCompare( b.name );
82
- } );
83
- return filters;
84
- }, [ fields, view ] );
85
- }
86
-
87
- export function FiltersToggle() {
88
- const {
89
- filters,
90
- view,
91
- onChangeView,
92
- setOpenedFilter,
93
- isShowingFilter,
94
- setIsShowingFilter,
95
- } = useContext( DataViewsContext );
96
-
97
- const buttonRef = useRef< HTMLButtonElement >( null );
98
- const onChangeViewWithFilterVisibility = useCallback(
99
- ( _view: View ) => {
100
- onChangeView( _view );
101
- setIsShowingFilter( true );
102
- },
103
- [ onChangeView, setIsShowingFilter ]
104
- );
105
- const visibleFilters = filters.filter( ( filter ) => filter.isVisible );
106
-
107
- const hasVisibleFilters = !! visibleFilters.length;
108
- if ( filters.length === 0 ) {
109
- return null;
110
- }
111
-
112
- const addFilterButtonProps = {
113
- label: __( 'Add filter' ),
114
- 'aria-expanded': false,
115
- isPressed: false,
116
- };
117
- const toggleFiltersButtonProps = {
118
- label: _x( 'Filter', 'verb' ),
119
- 'aria-expanded': isShowingFilter,
120
- isPressed: isShowingFilter,
121
- onClick: () => {
122
- if ( ! isShowingFilter ) {
123
- setOpenedFilter( null );
124
- }
125
- setIsShowingFilter( ! isShowingFilter );
126
- },
127
- };
128
- const buttonComponent = (
129
- <Button
130
- ref={ buttonRef }
131
- className="dataviews-filters__visibility-toggle"
132
- size="compact"
133
- icon={ funnel }
134
- { ...( hasVisibleFilters
135
- ? toggleFiltersButtonProps
136
- : addFilterButtonProps ) }
137
- />
138
- );
139
- return (
140
- <div className="dataviews-filters__container-visibility-toggle">
141
- { ! hasVisibleFilters ? (
142
- <AddFilterMenu
143
- filters={ filters }
144
- view={ view }
145
- onChangeView={ onChangeViewWithFilterVisibility }
146
- setOpenedFilter={ setOpenedFilter }
147
- triggerProps={ { render: buttonComponent } }
148
- />
149
- ) : (
150
- <FilterVisibilityToggle
151
- buttonRef={ buttonRef }
152
- filtersCount={ view.filters?.length }
153
- >
154
- { buttonComponent }
155
- </FilterVisibilityToggle>
156
- ) }
157
- </div>
158
- );
159
- }
160
-
161
- function FilterVisibilityToggle( {
162
- buttonRef,
163
- filtersCount,
164
- children,
165
- }: {
166
- buttonRef: React.RefObject< HTMLButtonElement >;
167
- filtersCount?: number;
168
- children: React.ReactNode;
169
- } ) {
170
- // Focus the `add filter` button when unmounts.
171
- useEffect(
172
- () => () => {
173
- buttonRef.current?.focus();
174
- },
175
- [ buttonRef ]
176
- );
177
- return (
178
- <>
179
- { children }
180
- { !! filtersCount && (
181
- <span className="dataviews-filters-toggle__count">
182
- { filtersCount }
183
- </span>
184
- ) }
185
- </>
186
- );
187
- }
188
-
189
- function Filters( { className }: { className?: string } ) {
190
- const { fields, view, onChangeView, openedFilter, setOpenedFilter } =
191
- useContext( DataViewsContext );
192
- const addFilterRef = useRef< HTMLButtonElement >( null );
193
- const filters = useFilters( fields, view );
194
- const addFilter = (
195
- <AddFilter
196
- key="add-filter"
197
- filters={ filters }
198
- view={ view }
199
- onChangeView={ onChangeView }
200
- ref={ addFilterRef }
201
- setOpenedFilter={ setOpenedFilter }
202
- />
203
- );
204
- const visibleFilters = filters.filter( ( filter ) => filter.isVisible );
205
- if ( visibleFilters.length === 0 ) {
206
- return null;
207
- }
208
- const filterComponents = [
209
- ...visibleFilters.map( ( filter ) => {
210
- return (
211
- <Filter
212
- key={ filter.field }
213
- filter={ filter }
214
- view={ view }
215
- fields={ fields }
216
- onChangeView={ onChangeView }
217
- addFilterRef={ addFilterRef }
218
- openedFilter={ openedFilter }
219
- />
220
- );
221
- } ),
222
- addFilter,
223
- ];
224
-
225
- filterComponents.push(
226
- <ResetFilters
227
- key="reset-filters"
228
- filters={ filters }
229
- view={ view }
230
- onChangeView={ onChangeView }
231
- />
232
- );
233
-
234
- return (
235
- <HStack
236
- justify="flex-start"
237
- style={ { width: 'fit-content' } }
238
- wrap
239
- className={ className }
240
- >
241
- { filterComponents }
242
- </HStack>
243
- );
244
- }
245
-
246
- export default memo( Filters );
1
+ export { default as Filters } from './filters';
2
+ export { default as FiltersToggle } from './toggle';
3
+ export { default as useFilters } from './use-filters';
4
+ export { default as FiltersToggled } from './filters-toggled';
@@ -0,0 +1,118 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useContext, useRef, useCallback, useEffect } from '@wordpress/element';
5
+ import { Button } from '@wordpress/components';
6
+ import { funnel } from '@wordpress/icons';
7
+ import { __, _x } from '@wordpress/i18n';
8
+
9
+ /**
10
+ * Internal dependencies
11
+ */
12
+ import { AddFilterMenu } from './add-filter';
13
+ import DataViewsContext from '../dataviews-context';
14
+ import type { View } from '../../types';
15
+
16
+ function FiltersToggle() {
17
+ const {
18
+ filters,
19
+ view,
20
+ onChangeView,
21
+ setOpenedFilter,
22
+ isShowingFilter,
23
+ setIsShowingFilter,
24
+ } = useContext( DataViewsContext );
25
+
26
+ const buttonRef = useRef< HTMLButtonElement >( null );
27
+ const onChangeViewWithFilterVisibility = useCallback(
28
+ ( _view: View ) => {
29
+ onChangeView( _view );
30
+ setIsShowingFilter( true );
31
+ },
32
+ [ onChangeView, setIsShowingFilter ]
33
+ );
34
+ const visibleFilters = filters.filter( ( filter ) => filter.isVisible );
35
+
36
+ const hasVisibleFilters = !! visibleFilters.length;
37
+ if ( filters.length === 0 ) {
38
+ return null;
39
+ }
40
+
41
+ const addFilterButtonProps = {
42
+ label: __( 'Add filter' ),
43
+ 'aria-expanded': false,
44
+ isPressed: false,
45
+ };
46
+ const toggleFiltersButtonProps = {
47
+ label: _x( 'Filter', 'verb' ),
48
+ 'aria-expanded': isShowingFilter,
49
+ isPressed: isShowingFilter,
50
+ onClick: () => {
51
+ if ( ! isShowingFilter ) {
52
+ setOpenedFilter( null );
53
+ }
54
+ setIsShowingFilter( ! isShowingFilter );
55
+ },
56
+ };
57
+ const buttonComponent = (
58
+ <Button
59
+ ref={ buttonRef }
60
+ className="dataviews-filters__visibility-toggle"
61
+ size="compact"
62
+ icon={ funnel }
63
+ { ...( hasVisibleFilters
64
+ ? toggleFiltersButtonProps
65
+ : addFilterButtonProps ) }
66
+ />
67
+ );
68
+ return (
69
+ <div className="dataviews-filters__container-visibility-toggle">
70
+ { ! hasVisibleFilters ? (
71
+ <AddFilterMenu
72
+ filters={ filters }
73
+ view={ view }
74
+ onChangeView={ onChangeViewWithFilterVisibility }
75
+ setOpenedFilter={ setOpenedFilter }
76
+ triggerProps={ { render: buttonComponent } }
77
+ />
78
+ ) : (
79
+ <FilterVisibilityToggle
80
+ buttonRef={ buttonRef }
81
+ filtersCount={ view.filters?.length }
82
+ >
83
+ { buttonComponent }
84
+ </FilterVisibilityToggle>
85
+ ) }
86
+ </div>
87
+ );
88
+ }
89
+
90
+ function FilterVisibilityToggle( {
91
+ buttonRef,
92
+ filtersCount,
93
+ children,
94
+ }: {
95
+ buttonRef: React.RefObject< HTMLButtonElement >;
96
+ filtersCount?: number;
97
+ children: React.ReactNode;
98
+ } ) {
99
+ // Focus the `add filter` button when unmounts.
100
+ useEffect(
101
+ () => () => {
102
+ buttonRef.current?.focus();
103
+ },
104
+ [ buttonRef ]
105
+ );
106
+ return (
107
+ <>
108
+ { children }
109
+ { !! filtersCount && (
110
+ <span className="dataviews-filters-toggle__count">
111
+ { filtersCount }
112
+ </span>
113
+ ) }
114
+ </>
115
+ );
116
+ }
117
+
118
+ export default FiltersToggle;