@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.
- package/CHANGELOG.md +19 -3
- package/README.md +4 -2
- package/build/components/dataviews/index.js +4 -6
- package/build/components/dataviews/index.js.map +1 -1
- package/build/components/dataviews-filters/filters-toggled.js +32 -0
- package/build/components/dataviews-filters/filters-toggled.js.map +1 -0
- package/build/components/dataviews-filters/filters.js +73 -0
- package/build/components/dataviews-filters/filters.js.map +1 -0
- package/build/components/dataviews-filters/index.js +26 -190
- package/build/components/dataviews-filters/index.js.map +1 -1
- package/build/components/dataviews-filters/toggle.js +99 -0
- package/build/components/dataviews-filters/toggle.js.map +1 -0
- package/build/components/dataviews-filters/use-filters.js +63 -0
- package/build/components/dataviews-filters/use-filters.js.map +1 -0
- package/build/components/dataviews-picker/index.js +4 -6
- package/build/components/dataviews-picker/index.js.map +1 -1
- package/build/components/dataviews-view-config/index.js +22 -3
- package/build/components/dataviews-view-config/index.js.map +1 -1
- package/build/dataform-controls/array.js +110 -24
- package/build/dataform-controls/array.js.map +1 -1
- package/build/dataviews-layouts/picker-grid/index.js +4 -1
- package/build/dataviews-layouts/picker-grid/index.js.map +1 -1
- package/build/field-types/array.js +0 -6
- package/build/field-types/array.js.map +1 -1
- package/build/index.js +7 -0
- package/build/index.js.map +1 -1
- package/build/types.js.map +1 -1
- package/build/validation.js +18 -1
- package/build/validation.js.map +1 -1
- package/build-module/components/dataviews/index.js +5 -7
- package/build-module/components/dataviews/index.js.map +1 -1
- package/build-module/components/dataviews-filters/filters-toggled.js +24 -0
- package/build-module/components/dataviews-filters/filters-toggled.js.map +1 -0
- package/build-module/components/dataviews-filters/filters.js +65 -0
- package/build-module/components/dataviews-filters/filters.js.map +1 -0
- package/build-module/components/dataviews-filters/index.js +4 -186
- package/build-module/components/dataviews-filters/index.js.map +1 -1
- package/build-module/components/dataviews-filters/toggle.js +91 -0
- package/build-module/components/dataviews-filters/toggle.js.map +1 -0
- package/build-module/components/dataviews-filters/use-filters.js +56 -0
- package/build-module/components/dataviews-filters/use-filters.js.map +1 -0
- package/build-module/components/dataviews-picker/index.js +5 -7
- package/build-module/components/dataviews-picker/index.js.map +1 -1
- package/build-module/components/dataviews-view-config/index.js +22 -3
- package/build-module/components/dataviews-view-config/index.js.map +1 -1
- package/build-module/dataform-controls/array.js +112 -26
- package/build-module/dataform-controls/array.js.map +1 -1
- package/build-module/dataviews-layouts/picker-grid/index.js +4 -1
- package/build-module/dataviews-layouts/picker-grid/index.js.map +1 -1
- package/build-module/field-types/array.js +0 -6
- package/build-module/field-types/array.js.map +1 -1
- package/build-module/index.js +1 -0
- package/build-module/index.js.map +1 -1
- package/build-module/types.js.map +1 -1
- package/build-module/validation.js +18 -1
- package/build-module/validation.js.map +1 -1
- package/build-types/components/dataform/stories/index.story.d.ts.map +1 -1
- package/build-types/components/dataviews/index.d.ts +3 -2
- package/build-types/components/dataviews/index.d.ts.map +1 -1
- package/build-types/components/dataviews-filters/filters-toggled.d.ts +5 -0
- package/build-types/components/dataviews-filters/filters-toggled.d.ts.map +1 -0
- package/build-types/components/dataviews-filters/filters.d.ts +6 -0
- package/build-types/components/dataviews-filters/filters.d.ts.map +1 -0
- package/build-types/components/dataviews-filters/index.d.ts +4 -8
- package/build-types/components/dataviews-filters/index.d.ts.map +1 -1
- package/build-types/components/dataviews-filters/toggle.d.ts +3 -0
- package/build-types/components/dataviews-filters/toggle.d.ts.map +1 -0
- package/build-types/components/dataviews-filters/use-filters.d.ts +4 -0
- package/build-types/components/dataviews-filters/use-filters.d.ts.map +1 -0
- package/build-types/components/dataviews-picker/index.d.ts +3 -2
- package/build-types/components/dataviews-picker/index.d.ts.map +1 -1
- package/build-types/components/dataviews-view-config/index.d.ts.map +1 -1
- package/build-types/dataform-controls/array.d.ts.map +1 -1
- package/build-types/dataviews-layouts/picker-grid/index.d.ts.map +1 -1
- package/build-types/field-types/array.d.ts.map +1 -1
- package/build-types/index.d.ts +1 -0
- package/build-types/index.d.ts.map +1 -1
- package/build-types/types.d.ts +2 -1
- package/build-types/types.d.ts.map +1 -1
- package/build-types/validation.d.ts.map +1 -1
- package/build-wp/index.js +899 -408
- package/package.json +15 -15
- package/src/components/dataform/stories/index.story.tsx +73 -1
- package/src/components/dataviews/index.tsx +8 -14
- package/src/components/dataviews/stories/index.story.tsx +1 -1
- package/src/components/dataviews-filters/filters-toggled.tsx +20 -0
- package/src/components/dataviews-filters/filters.tsx +73 -0
- package/src/components/dataviews-filters/index.tsx +4 -246
- package/src/components/dataviews-filters/toggle.tsx +118 -0
- package/src/components/dataviews-filters/use-filters.ts +73 -0
- package/src/components/dataviews-picker/index.tsx +8 -14
- package/src/components/dataviews-view-config/index.tsx +18 -3
- package/src/dataform-controls/array.tsx +137 -40
- package/src/dataviews-layouts/picker-grid/index.tsx +15 -8
- package/src/field-types/array.tsx +0 -8
- package/src/index.ts +1 -0
- package/src/test/validation.ts +192 -0
- package/src/types.ts +2 -1
- package/src/validation.ts +30 -0
- package/tsconfig.tsbuildinfo +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordpress/dataviews",
|
|
3
|
-
"version": "9.
|
|
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.
|
|
50
|
-
"@wordpress/components": "^30.
|
|
51
|
-
"@wordpress/compose": "^7.
|
|
52
|
-
"@wordpress/data": "^10.
|
|
53
|
-
"@wordpress/date": "^5.
|
|
54
|
-
"@wordpress/element": "^6.
|
|
55
|
-
"@wordpress/i18n": "^6.
|
|
56
|
-
"@wordpress/icons": "^10.
|
|
57
|
-
"@wordpress/keycodes": "^4.
|
|
58
|
-
"@wordpress/primitives": "^4.
|
|
59
|
-
"@wordpress/private-apis": "^1.
|
|
60
|
-
"@wordpress/url": "^4.
|
|
61
|
-
"@wordpress/warning": "^3.
|
|
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": "
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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.
|
|
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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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;
|