@wordpress/dataviews 13.1.1-next.v.202603102151.0 → 14.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.
- package/CHANGELOG.md +18 -1
- package/README.md +19 -3
- package/build/components/dataform-controls/datetime.cjs +8 -4
- package/build/components/dataform-controls/datetime.cjs.map +2 -2
- package/build/components/dataform-layouts/card/index.cjs +132 -128
- package/build/components/dataform-layouts/card/index.cjs.map +3 -3
- package/build/components/dataviews-bulk-actions/index.cjs +28 -5
- package/build/components/dataviews-bulk-actions/index.cjs.map +2 -2
- package/build/components/dataviews-context/index.cjs +2 -2
- package/build/components/dataviews-context/index.cjs.map +2 -2
- package/build/components/dataviews-footer/index.cjs +2 -3
- package/build/components/dataviews-footer/index.cjs.map +2 -2
- package/build/components/dataviews-layout/index.cjs +12 -3
- package/build/components/dataviews-layout/index.cjs.map +2 -2
- package/build/components/dataviews-layouts/grid/composite-grid.cjs +378 -245
- package/build/components/dataviews-layouts/grid/composite-grid.cjs.map +2 -2
- package/build/components/dataviews-layouts/index.cjs +3 -3
- package/build/components/dataviews-layouts/index.cjs.map +3 -3
- package/build/components/dataviews-layouts/picker-grid/index.cjs +76 -32
- package/build/components/dataviews-layouts/picker-grid/index.cjs.map +2 -2
- package/build/components/dataviews-layouts/picker-table/index.cjs +34 -22
- package/build/components/dataviews-layouts/picker-table/index.cjs.map +2 -2
- package/build/components/dataviews-layouts/table/index.cjs +97 -88
- package/build/components/dataviews-layouts/table/index.cjs.map +2 -2
- package/build/components/dataviews-layouts/table/{use-is-horizontal-scroll-end.cjs → use-scroll-state.cjs} +29 -33
- package/build/components/dataviews-layouts/table/use-scroll-state.cjs.map +7 -0
- package/build/components/dataviews-layouts/utils/density-picker.cjs.map +2 -2
- package/build/components/dataviews-layouts/utils/grid-config-options.cjs +45 -0
- package/build/components/dataviews-layouts/utils/grid-config-options.cjs.map +7 -0
- package/build/components/dataviews-layouts/utils/use-infinite-scroll.cjs +62 -0
- package/build/components/dataviews-layouts/utils/use-infinite-scroll.cjs.map +7 -0
- package/build/components/dataviews-picker-footer/index.cjs +23 -4
- package/build/components/dataviews-picker-footer/index.cjs.map +2 -2
- package/build/components/dataviews-search/index.cjs +2 -1
- package/build/components/dataviews-search/index.cjs.map +2 -2
- package/build/components/dataviews-selection-checkbox/index.cjs +3 -2
- package/build/components/dataviews-selection-checkbox/index.cjs.map +2 -2
- package/build/components/dataviews-view-config/index.cjs +0 -2
- package/build/components/dataviews-view-config/index.cjs.map +3 -3
- package/build/components/dataviews-view-config/infinite-scroll-toggle.cjs +0 -3
- package/build/components/dataviews-view-config/infinite-scroll-toggle.cjs.map +2 -2
- package/build/dataviews/index.cjs +38 -34
- package/build/dataviews/index.cjs.map +3 -3
- package/build/dataviews-picker/index.cjs +26 -25
- package/build/dataviews-picker/index.cjs.map +3 -3
- package/build/hooks/index.cjs +11 -2
- package/build/hooks/index.cjs.map +2 -2
- package/build/hooks/use-data.cjs +146 -9
- package/build/hooks/use-data.cjs.map +2 -2
- package/build/hooks/use-infinite-scroll.cjs +208 -0
- package/build/hooks/use-infinite-scroll.cjs.map +7 -0
- package/build/hooks/use-selected-items.cjs +57 -0
- package/build/hooks/use-selected-items.cjs.map +7 -0
- package/build/types/dataviews.cjs.map +1 -1
- package/build/types/field-api.cjs.map +1 -1
- package/build/utils/filter-sort-and-paginate.cjs +5 -1
- package/build/utils/filter-sort-and-paginate.cjs.map +2 -2
- package/build/utils/get-footer-message.cjs +8 -8
- package/build/utils/get-footer-message.cjs.map +2 -2
- package/build-module/components/dataform-controls/datetime.mjs +8 -4
- package/build-module/components/dataform-controls/datetime.mjs.map +2 -2
- package/build-module/components/dataform-layouts/card/index.mjs +132 -133
- package/build-module/components/dataform-layouts/card/index.mjs.map +2 -2
- package/build-module/components/dataviews-bulk-actions/index.mjs +28 -5
- package/build-module/components/dataviews-bulk-actions/index.mjs.map +2 -2
- package/build-module/components/dataviews-context/index.mjs +2 -2
- package/build-module/components/dataviews-context/index.mjs.map +2 -2
- package/build-module/components/dataviews-footer/index.mjs +2 -3
- package/build-module/components/dataviews-footer/index.mjs.map +2 -2
- package/build-module/components/dataviews-layout/index.mjs +12 -3
- package/build-module/components/dataviews-layout/index.mjs.map +2 -2
- package/build-module/components/dataviews-layouts/grid/composite-grid.mjs +387 -246
- package/build-module/components/dataviews-layouts/grid/composite-grid.mjs.map +2 -2
- package/build-module/components/dataviews-layouts/index.mjs +3 -3
- package/build-module/components/dataviews-layouts/index.mjs.map +2 -2
- package/build-module/components/dataviews-layouts/picker-grid/index.mjs +80 -33
- package/build-module/components/dataviews-layouts/picker-grid/index.mjs.map +2 -2
- package/build-module/components/dataviews-layouts/picker-table/index.mjs +34 -22
- package/build-module/components/dataviews-layouts/picker-table/index.mjs.map +2 -2
- package/build-module/components/dataviews-layouts/table/index.mjs +97 -88
- package/build-module/components/dataviews-layouts/table/index.mjs.map +2 -2
- package/build-module/components/dataviews-layouts/table/use-scroll-state.mjs +46 -0
- package/build-module/components/dataviews-layouts/table/use-scroll-state.mjs.map +7 -0
- package/build-module/components/dataviews-layouts/utils/density-picker.mjs.map +2 -2
- package/build-module/components/dataviews-layouts/utils/grid-config-options.mjs +14 -0
- package/build-module/components/dataviews-layouts/utils/grid-config-options.mjs.map +7 -0
- package/build-module/components/dataviews-layouts/utils/use-infinite-scroll.mjs +26 -0
- package/build-module/components/dataviews-layouts/utils/use-infinite-scroll.mjs.map +7 -0
- package/build-module/components/dataviews-picker-footer/index.mjs +23 -4
- package/build-module/components/dataviews-picker-footer/index.mjs.map +2 -2
- package/build-module/components/dataviews-search/index.mjs +2 -1
- package/build-module/components/dataviews-search/index.mjs.map +2 -2
- package/build-module/components/dataviews-selection-checkbox/index.mjs +3 -2
- package/build-module/components/dataviews-selection-checkbox/index.mjs.map +2 -2
- package/build-module/components/dataviews-view-config/index.mjs +0 -2
- package/build-module/components/dataviews-view-config/index.mjs.map +2 -2
- package/build-module/components/dataviews-view-config/infinite-scroll-toggle.mjs +0 -3
- package/build-module/components/dataviews-view-config/infinite-scroll-toggle.mjs.map +2 -2
- package/build-module/dataviews/index.mjs +46 -36
- package/build-module/dataviews/index.mjs.map +2 -2
- package/build-module/dataviews-picker/index.mjs +34 -27
- package/build-module/dataviews-picker/index.mjs.map +2 -2
- package/build-module/hooks/index.mjs +7 -1
- package/build-module/hooks/index.mjs.map +2 -2
- package/build-module/hooks/use-data.mjs +147 -10
- package/build-module/hooks/use-data.mjs.map +2 -2
- package/build-module/hooks/use-infinite-scroll.mjs +188 -0
- package/build-module/hooks/use-infinite-scroll.mjs.map +7 -0
- package/build-module/hooks/use-selected-items.mjs +36 -0
- package/build-module/hooks/use-selected-items.mjs.map +7 -0
- package/build-module/utils/filter-sort-and-paginate.mjs +5 -1
- package/build-module/utils/filter-sort-and-paginate.mjs.map +2 -2
- package/build-module/utils/get-footer-message.mjs +8 -8
- package/build-module/utils/get-footer-message.mjs.map +2 -2
- package/build-style/style-rtl.css +107 -41
- package/build-style/style.css +107 -41
- package/build-types/components/dataform-controls/datetime.d.ts +1 -1
- package/build-types/components/dataform-controls/datetime.d.ts.map +1 -1
- package/build-types/components/dataform-layouts/card/index.d.ts.map +1 -1
- package/build-types/components/dataviews-bulk-actions/index.d.ts +2 -1
- package/build-types/components/dataviews-bulk-actions/index.d.ts.map +1 -1
- package/build-types/components/dataviews-context/index.d.ts +1 -1
- package/build-types/components/dataviews-context/index.d.ts.map +1 -1
- package/build-types/components/dataviews-footer/index.d.ts.map +1 -1
- package/build-types/components/dataviews-layout/index.d.ts.map +1 -1
- package/build-types/components/dataviews-layouts/grid/composite-grid.d.ts.map +1 -1
- package/build-types/components/dataviews-layouts/index.d.ts +3 -3
- package/build-types/components/dataviews-layouts/index.d.ts.map +1 -1
- package/build-types/components/dataviews-layouts/picker-grid/index.d.ts.map +1 -1
- package/build-types/components/dataviews-layouts/picker-table/index.d.ts.map +1 -1
- package/build-types/components/dataviews-layouts/table/index.d.ts.map +1 -1
- package/build-types/components/dataviews-layouts/table/use-scroll-state.d.ts +25 -0
- package/build-types/components/dataviews-layouts/table/use-scroll-state.d.ts.map +1 -0
- package/build-types/components/dataviews-layouts/utils/density-picker.d.ts.map +1 -1
- package/build-types/components/dataviews-layouts/utils/grid-config-options.d.ts +2 -0
- package/build-types/components/dataviews-layouts/utils/grid-config-options.d.ts.map +1 -0
- package/build-types/components/dataviews-layouts/utils/use-infinite-scroll.d.ts +22 -0
- package/build-types/components/dataviews-layouts/utils/use-infinite-scroll.d.ts.map +1 -0
- package/build-types/components/dataviews-picker-footer/index.d.ts.map +1 -1
- package/build-types/components/dataviews-search/index.d.ts.map +1 -1
- package/build-types/components/dataviews-selection-checkbox/index.d.ts.map +1 -1
- package/build-types/components/dataviews-view-config/index.d.ts.map +1 -1
- package/build-types/components/dataviews-view-config/infinite-scroll-toggle.d.ts +1 -1
- package/build-types/components/dataviews-view-config/infinite-scroll-toggle.d.ts.map +1 -1
- package/build-types/dataviews/index.d.ts +0 -1
- package/build-types/dataviews/index.d.ts.map +1 -1
- package/build-types/dataviews/stories/empty.d.ts +1 -2
- package/build-types/dataviews/stories/empty.d.ts.map +1 -1
- package/build-types/dataviews/stories/fixtures.d.ts.map +1 -1
- package/build-types/dataviews/stories/free-composition.d.ts.map +1 -1
- package/build-types/dataviews/stories/index.story.d.ts +18 -10
- package/build-types/dataviews/stories/index.story.d.ts.map +1 -1
- package/build-types/dataviews/stories/infinite-scroll.d.ts.map +1 -1
- package/build-types/dataviews/stories/layout-activity.d.ts.map +1 -1
- package/build-types/dataviews/stories/layout-custom.d.ts +3 -1
- package/build-types/dataviews/stories/layout-custom.d.ts.map +1 -1
- package/build-types/dataviews/stories/layout-grid.d.ts.map +1 -1
- package/build-types/dataviews/stories/layout-list.d.ts.map +1 -1
- package/build-types/dataviews/stories/layout-table.d.ts.map +1 -1
- package/build-types/dataviews/stories/with-card.d.ts +3 -1
- package/build-types/dataviews/stories/with-card.d.ts.map +1 -1
- package/build-types/dataviews-picker/index.d.ts +0 -1
- package/build-types/dataviews-picker/index.d.ts.map +1 -1
- package/build-types/dataviews-picker/stories/fixtures.d.ts.map +1 -1
- package/build-types/dataviews-picker/stories/index.story.d.ts.map +1 -1
- package/build-types/field-types/stories/index.story.d.ts.map +1 -1
- package/build-types/hooks/index.d.ts +3 -0
- package/build-types/hooks/index.d.ts.map +1 -1
- package/build-types/hooks/test/use-data.d.ts +2 -0
- package/build-types/hooks/test/use-data.d.ts.map +1 -0
- package/build-types/hooks/use-data.d.ts +41 -3
- package/build-types/hooks/use-data.d.ts.map +1 -1
- package/build-types/hooks/use-infinite-scroll.d.ts +21 -0
- package/build-types/hooks/use-infinite-scroll.d.ts.map +1 -0
- package/build-types/hooks/use-selected-items.d.ts +19 -0
- package/build-types/hooks/use-selected-items.d.ts.map +1 -0
- package/build-types/types/dataviews.d.ts +15 -1
- package/build-types/types/dataviews.d.ts.map +1 -1
- package/build-types/types/field-api.d.ts +15 -4
- package/build-types/types/field-api.d.ts.map +1 -1
- package/build-types/utils/filter-sort-and-paginate.d.ts.map +1 -1
- package/build-types/utils/get-footer-message.d.ts +3 -2
- package/build-types/utils/get-footer-message.d.ts.map +1 -1
- package/build-wp/index.js +3202 -2761
- package/package.json +19 -19
- package/src/components/dataform-controls/datetime.tsx +19 -11
- package/src/components/dataform-layouts/card/index.tsx +171 -146
- package/src/components/dataform-layouts/card/style.scss +8 -5
- package/src/components/dataviews-bulk-actions/index.tsx +28 -1
- package/src/components/dataviews-context/index.ts +2 -2
- package/src/components/dataviews-footer/index.tsx +1 -6
- package/src/components/dataviews-layout/index.tsx +41 -19
- package/src/components/dataviews-layout/style.scss +8 -0
- package/src/components/dataviews-layouts/grid/composite-grid.tsx +433 -278
- package/src/components/dataviews-layouts/grid/style.scss +22 -2
- package/src/components/dataviews-layouts/index.ts +3 -3
- package/src/components/dataviews-layouts/picker-grid/index.tsx +70 -17
- package/src/components/dataviews-layouts/picker-grid/style.scss +10 -0
- package/src/components/dataviews-layouts/picker-table/index.tsx +42 -22
- package/src/components/dataviews-layouts/table/index.tsx +10 -4
- package/src/components/dataviews-layouts/table/style.scss +13 -0
- package/src/components/dataviews-layouts/table/use-scroll-state.ts +79 -0
- package/src/components/dataviews-layouts/utils/density-picker.tsx +12 -2
- package/src/components/dataviews-layouts/utils/grid-config-options.tsx +14 -0
- package/src/components/dataviews-layouts/utils/grid-items.scss +9 -1
- package/src/components/dataviews-layouts/utils/use-infinite-scroll.ts +64 -0
- package/src/components/dataviews-picker-footer/index.tsx +21 -1
- package/src/components/dataviews-search/index.tsx +2 -1
- package/src/components/dataviews-selection-checkbox/index.tsx +4 -2
- package/src/components/dataviews-view-config/index.tsx +0 -2
- package/src/components/dataviews-view-config/infinite-scroll-toggle.tsx +0 -5
- package/src/dataviews/index.tsx +58 -45
- package/src/dataviews/stories/empty.tsx +1 -3
- package/src/dataviews/stories/fixtures.tsx +288 -0
- package/src/dataviews/stories/free-composition.tsx +44 -45
- package/src/dataviews/stories/index.story.tsx +31 -8
- package/src/dataviews/stories/infinite-scroll.tsx +7 -93
- package/src/dataviews/stories/layout-activity.tsx +1 -0
- package/src/dataviews/stories/layout-custom.tsx +7 -3
- package/src/dataviews/stories/layout-grid.tsx +1 -0
- package/src/dataviews/stories/layout-list.tsx +1 -0
- package/src/dataviews/stories/layout-table.tsx +1 -0
- package/src/dataviews/stories/style.css +0 -5
- package/src/dataviews/stories/with-card.tsx +35 -24
- package/src/dataviews/style.scss +5 -8
- package/src/dataviews/test/dataviews.tsx +54 -1
- package/src/dataviews-picker/index.tsx +41 -35
- package/src/dataviews-picker/stories/fixtures.tsx +270 -0
- package/src/dataviews-picker/stories/index.story.tsx +62 -129
- package/src/field-types/stories/index.story.tsx +12 -0
- package/src/hooks/index.ts +3 -0
- package/src/hooks/test/use-data.ts +791 -0
- package/src/hooks/use-data.ts +288 -21
- package/src/hooks/use-infinite-scroll.ts +304 -0
- package/src/hooks/use-selected-items.ts +72 -0
- package/src/style.scss +1 -0
- package/src/types/dataviews.ts +18 -1
- package/src/types/field-api.ts +16 -3
- package/src/utils/filter-sort-and-paginate.ts +13 -1
- package/src/utils/get-footer-message.ts +12 -9
- package/src/utils/test/filter-sort-and-paginate.js +78 -54
- package/build/components/dataviews-layouts/table/use-is-horizontal-scroll-end.cjs.map +0 -7
- package/build-module/components/dataviews-layouts/table/use-is-horizontal-scroll-end.mjs +0 -50
- package/build-module/components/dataviews-layouts/table/use-is-horizontal-scroll-end.mjs.map +0 -7
- package/build-types/components/dataviews-layouts/table/use-is-horizontal-scroll-end.d.ts +0 -19
- package/build-types/components/dataviews-layouts/table/use-is-horizontal-scroll-end.d.ts.map +0 -1
- package/src/components/dataviews-layouts/table/use-is-horizontal-scroll-end.ts +0 -82
|
@@ -0,0 +1,791 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { renderHook, act } from '@testing-library/react';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Internal dependencies
|
|
8
|
+
*/
|
|
9
|
+
import useData from '../use-data';
|
|
10
|
+
import type { View } from '../../types';
|
|
11
|
+
|
|
12
|
+
type TestItem = { id: number; name?: string };
|
|
13
|
+
|
|
14
|
+
const getItemId = ( item: TestItem ) => String( item.id );
|
|
15
|
+
const defaultPaginationInfo = { totalItems: 100, totalPages: 10 };
|
|
16
|
+
|
|
17
|
+
describe( 'useData', () => {
|
|
18
|
+
describe( 'when infinite scroll is disabled', () => {
|
|
19
|
+
it( 'returns provided data unchanged', () => {
|
|
20
|
+
const data: TestItem[] = [
|
|
21
|
+
{ id: 1, name: 'Item 1' },
|
|
22
|
+
{ id: 2, name: 'Item 2' },
|
|
23
|
+
];
|
|
24
|
+
const view = {
|
|
25
|
+
type: 'table',
|
|
26
|
+
infiniteScrollEnabled: false,
|
|
27
|
+
} as View;
|
|
28
|
+
|
|
29
|
+
const { result } = renderHook( () =>
|
|
30
|
+
useData( {
|
|
31
|
+
view,
|
|
32
|
+
data,
|
|
33
|
+
getItemId,
|
|
34
|
+
paginationInfo: defaultPaginationInfo,
|
|
35
|
+
} )
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
expect( result.current.data ).toEqual( data );
|
|
39
|
+
expect( result.current.setVisibleEntries ).toBeUndefined();
|
|
40
|
+
} );
|
|
41
|
+
|
|
42
|
+
it( 'returns empty array when data is empty', () => {
|
|
43
|
+
const data: TestItem[] = [];
|
|
44
|
+
const view = {
|
|
45
|
+
type: 'table',
|
|
46
|
+
infiniteScrollEnabled: false,
|
|
47
|
+
} as View;
|
|
48
|
+
|
|
49
|
+
const { result } = renderHook( () =>
|
|
50
|
+
useData( {
|
|
51
|
+
view,
|
|
52
|
+
data,
|
|
53
|
+
getItemId,
|
|
54
|
+
paginationInfo: defaultPaginationInfo,
|
|
55
|
+
} )
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
expect( result.current.data ).toEqual( [] );
|
|
59
|
+
} );
|
|
60
|
+
} );
|
|
61
|
+
|
|
62
|
+
describe( 'when infinite scroll is enabled', () => {
|
|
63
|
+
describe( 'initial load', () => {
|
|
64
|
+
it( 'assigns positions starting from 1 by default', () => {
|
|
65
|
+
const data: TestItem[] = [
|
|
66
|
+
{ id: 1, name: 'Item 1' },
|
|
67
|
+
{ id: 2, name: 'Item 2' },
|
|
68
|
+
];
|
|
69
|
+
const view = {
|
|
70
|
+
type: 'table',
|
|
71
|
+
infiniteScrollEnabled: true,
|
|
72
|
+
} as View;
|
|
73
|
+
|
|
74
|
+
const { result } = renderHook( () =>
|
|
75
|
+
useData( {
|
|
76
|
+
view,
|
|
77
|
+
data,
|
|
78
|
+
getItemId,
|
|
79
|
+
paginationInfo: defaultPaginationInfo,
|
|
80
|
+
} )
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
expect( result.current.data ).toHaveLength( 2 );
|
|
84
|
+
expect(
|
|
85
|
+
(
|
|
86
|
+
result.current.data[ 0 ] as TestItem & {
|
|
87
|
+
position: number;
|
|
88
|
+
}
|
|
89
|
+
).position
|
|
90
|
+
).toBe( 1 );
|
|
91
|
+
expect(
|
|
92
|
+
(
|
|
93
|
+
result.current.data[ 1 ] as TestItem & {
|
|
94
|
+
position: number;
|
|
95
|
+
}
|
|
96
|
+
).position
|
|
97
|
+
).toBe( 2 );
|
|
98
|
+
} );
|
|
99
|
+
|
|
100
|
+
it( 'assigns positions starting from view.startPosition when provided', () => {
|
|
101
|
+
const data: TestItem[] = [
|
|
102
|
+
{ id: 1, name: 'Item 1' },
|
|
103
|
+
{ id: 2, name: 'Item 2' },
|
|
104
|
+
];
|
|
105
|
+
const view = {
|
|
106
|
+
type: 'table',
|
|
107
|
+
infiniteScrollEnabled: true,
|
|
108
|
+
startPosition: 5,
|
|
109
|
+
} as View;
|
|
110
|
+
|
|
111
|
+
const { result } = renderHook( () =>
|
|
112
|
+
useData( {
|
|
113
|
+
view,
|
|
114
|
+
data,
|
|
115
|
+
getItemId,
|
|
116
|
+
paginationInfo: defaultPaginationInfo,
|
|
117
|
+
} )
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
expect(
|
|
121
|
+
(
|
|
122
|
+
result.current.data[ 1 ] as TestItem & {
|
|
123
|
+
position: number;
|
|
124
|
+
}
|
|
125
|
+
).position
|
|
126
|
+
).toBe( 6 );
|
|
127
|
+
} );
|
|
128
|
+
|
|
129
|
+
it( 'returns setVisibleEntries callback', () => {
|
|
130
|
+
const data: TestItem[] = [ { id: 1 } ];
|
|
131
|
+
const view = {
|
|
132
|
+
type: 'table',
|
|
133
|
+
infiniteScrollEnabled: true,
|
|
134
|
+
} as View;
|
|
135
|
+
|
|
136
|
+
const { result } = renderHook( () =>
|
|
137
|
+
useData( {
|
|
138
|
+
view,
|
|
139
|
+
data,
|
|
140
|
+
getItemId,
|
|
141
|
+
paginationInfo: defaultPaginationInfo,
|
|
142
|
+
} )
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
expect( result.current.setVisibleEntries ).toBeDefined();
|
|
146
|
+
expect( typeof result.current.setVisibleEntries ).toBe(
|
|
147
|
+
'function'
|
|
148
|
+
);
|
|
149
|
+
} );
|
|
150
|
+
} );
|
|
151
|
+
|
|
152
|
+
describe( 'loading more data when scrolling down', () => {
|
|
153
|
+
it( 'appends new items with positions after existing items', () => {
|
|
154
|
+
const initialData: TestItem[] = [
|
|
155
|
+
{ id: 1, name: 'Item 1' },
|
|
156
|
+
{ id: 2, name: 'Item 2' },
|
|
157
|
+
];
|
|
158
|
+
const initialView = {
|
|
159
|
+
type: 'table',
|
|
160
|
+
infiniteScrollEnabled: true,
|
|
161
|
+
startPosition: 1,
|
|
162
|
+
} as View;
|
|
163
|
+
|
|
164
|
+
const { result, rerender } = renderHook(
|
|
165
|
+
( { view, data } ) =>
|
|
166
|
+
useData( {
|
|
167
|
+
view,
|
|
168
|
+
data,
|
|
169
|
+
getItemId,
|
|
170
|
+
paginationInfo: defaultPaginationInfo,
|
|
171
|
+
} ),
|
|
172
|
+
{ initialProps: { view: initialView, data: initialData } }
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
expect( result.current.data ).toHaveLength( 2 );
|
|
176
|
+
|
|
177
|
+
// Simulate scroll down - new page of data
|
|
178
|
+
const newData: TestItem[] = [
|
|
179
|
+
{ id: 3, name: 'Item 3' },
|
|
180
|
+
{ id: 4, name: 'Item 4' },
|
|
181
|
+
];
|
|
182
|
+
const newView = {
|
|
183
|
+
...initialView,
|
|
184
|
+
startPosition: 3,
|
|
185
|
+
} as View;
|
|
186
|
+
|
|
187
|
+
rerender( { view: newView, data: newData } );
|
|
188
|
+
|
|
189
|
+
// Should have all 4 items
|
|
190
|
+
expect( result.current.data ).toHaveLength( 4 );
|
|
191
|
+
// Items should be sorted by position
|
|
192
|
+
const positions = result.current.data.map(
|
|
193
|
+
( d: TestItem & { position?: number } ) =>
|
|
194
|
+
( d as TestItem & { position: number } ).position
|
|
195
|
+
);
|
|
196
|
+
expect( positions ).toEqual( [ 1, 2, 3, 4 ] );
|
|
197
|
+
} );
|
|
198
|
+
|
|
199
|
+
it( 'preserves positions for existing items', () => {
|
|
200
|
+
const initialData: TestItem[] = [ { id: 1 }, { id: 2 } ];
|
|
201
|
+
const initialView = {
|
|
202
|
+
type: 'table',
|
|
203
|
+
infiniteScrollEnabled: true,
|
|
204
|
+
startPosition: 1,
|
|
205
|
+
} as View;
|
|
206
|
+
|
|
207
|
+
const { result, rerender } = renderHook(
|
|
208
|
+
( { view, data } ) =>
|
|
209
|
+
useData( {
|
|
210
|
+
view,
|
|
211
|
+
data,
|
|
212
|
+
getItemId,
|
|
213
|
+
paginationInfo: defaultPaginationInfo,
|
|
214
|
+
} ),
|
|
215
|
+
{ initialProps: { view: initialView, data: initialData } }
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
// Scroll down with overlapping data
|
|
219
|
+
const newData: TestItem[] = [
|
|
220
|
+
{ id: 2 }, // Already exists
|
|
221
|
+
{ id: 3 }, // New
|
|
222
|
+
];
|
|
223
|
+
const newView = { ...initialView, startPosition: 2 } as View;
|
|
224
|
+
|
|
225
|
+
rerender( { view: newView, data: newData } );
|
|
226
|
+
|
|
227
|
+
// Item 2 should keep its original position (2)
|
|
228
|
+
const item2 = result.current.data.find(
|
|
229
|
+
( d: TestItem & { position?: number } ) => d.id === 2
|
|
230
|
+
) as TestItem & { position: number };
|
|
231
|
+
expect( item2.position ).toBe( 2 );
|
|
232
|
+
|
|
233
|
+
// Item 3 should get position 3
|
|
234
|
+
const item3 = result.current.data.find(
|
|
235
|
+
( d: TestItem & { position?: number } ) => d.id === 3
|
|
236
|
+
) as TestItem & { position: number };
|
|
237
|
+
expect( item3.position ).toBe( 3 );
|
|
238
|
+
} );
|
|
239
|
+
} );
|
|
240
|
+
|
|
241
|
+
describe( 'loading more data when scrolling up', () => {
|
|
242
|
+
it( 'prepends new items with positions before existing items', () => {
|
|
243
|
+
// Start with items at positions 5, 6
|
|
244
|
+
const initialData: TestItem[] = [
|
|
245
|
+
{ id: 5, name: 'Item 5' },
|
|
246
|
+
{ id: 6, name: 'Item 6' },
|
|
247
|
+
];
|
|
248
|
+
const initialView = {
|
|
249
|
+
type: 'table',
|
|
250
|
+
infiniteScrollEnabled: true,
|
|
251
|
+
startPosition: 5,
|
|
252
|
+
} as View;
|
|
253
|
+
|
|
254
|
+
const { result, rerender } = renderHook(
|
|
255
|
+
( { view, data } ) =>
|
|
256
|
+
useData( {
|
|
257
|
+
view,
|
|
258
|
+
data,
|
|
259
|
+
getItemId,
|
|
260
|
+
paginationInfo: defaultPaginationInfo,
|
|
261
|
+
} ),
|
|
262
|
+
{ initialProps: { view: initialView, data: initialData } }
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
expect( result.current.data ).toHaveLength( 2 );
|
|
266
|
+
|
|
267
|
+
// Simulate scroll up - load earlier data
|
|
268
|
+
const newData: TestItem[] = [
|
|
269
|
+
{ id: 3, name: 'Item 3' },
|
|
270
|
+
{ id: 4, name: 'Item 4' },
|
|
271
|
+
];
|
|
272
|
+
const newView = {
|
|
273
|
+
...initialView,
|
|
274
|
+
startPosition: 3, // Scrolling up
|
|
275
|
+
} as View;
|
|
276
|
+
|
|
277
|
+
rerender( { view: newView, data: newData } );
|
|
278
|
+
|
|
279
|
+
// Should have all 4 items
|
|
280
|
+
expect( result.current.data ).toHaveLength( 4 );
|
|
281
|
+
// Items should be sorted by position (ascending)
|
|
282
|
+
const ids = result.current.data.map(
|
|
283
|
+
( d: TestItem & { position?: number } ) => d.id
|
|
284
|
+
);
|
|
285
|
+
expect( ids ).toEqual( [ 3, 4, 5, 6 ] );
|
|
286
|
+
} );
|
|
287
|
+
} );
|
|
288
|
+
|
|
289
|
+
describe( 'deduplication', () => {
|
|
290
|
+
it( 'removes duplicates when new data overlaps with existing data', () => {
|
|
291
|
+
const initialData: TestItem[] = [
|
|
292
|
+
{ id: 1 },
|
|
293
|
+
{ id: 2 },
|
|
294
|
+
{ id: 3 },
|
|
295
|
+
];
|
|
296
|
+
const initialView = {
|
|
297
|
+
type: 'table',
|
|
298
|
+
infiniteScrollEnabled: true,
|
|
299
|
+
startPosition: 1,
|
|
300
|
+
} as View;
|
|
301
|
+
|
|
302
|
+
const { result, rerender } = renderHook(
|
|
303
|
+
( { view, data } ) =>
|
|
304
|
+
useData( {
|
|
305
|
+
view,
|
|
306
|
+
data,
|
|
307
|
+
getItemId,
|
|
308
|
+
paginationInfo: defaultPaginationInfo,
|
|
309
|
+
} ),
|
|
310
|
+
{ initialProps: { view: initialView, data: initialData } }
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
// New data with overlapping items
|
|
314
|
+
const newData: TestItem[] = [ { id: 2 }, { id: 3 }, { id: 4 } ];
|
|
315
|
+
const newView = { ...initialView, startPosition: 2 } as View;
|
|
316
|
+
|
|
317
|
+
rerender( { view: newView, data: newData } );
|
|
318
|
+
|
|
319
|
+
// Should not have duplicate IDs
|
|
320
|
+
const ids = result.current.data.map(
|
|
321
|
+
( d: TestItem & { position?: number } ) => d.id
|
|
322
|
+
);
|
|
323
|
+
const uniqueIds = [ ...new Set( ids ) ];
|
|
324
|
+
expect( ids ).toEqual( uniqueIds );
|
|
325
|
+
} );
|
|
326
|
+
} );
|
|
327
|
+
|
|
328
|
+
describe( 'buffer and unloading', () => {
|
|
329
|
+
it( 'keeps selected items even when outside visible buffer', () => {
|
|
330
|
+
const initialData: TestItem[] = Array.from(
|
|
331
|
+
{ length: 30 },
|
|
332
|
+
( _, i ) => ( { id: i + 1 } )
|
|
333
|
+
);
|
|
334
|
+
const initialView = {
|
|
335
|
+
type: 'table',
|
|
336
|
+
infiniteScrollEnabled: true,
|
|
337
|
+
startPosition: 1,
|
|
338
|
+
} as View;
|
|
339
|
+
|
|
340
|
+
const { result, rerender } = renderHook(
|
|
341
|
+
( { view, data, selection } ) =>
|
|
342
|
+
useData( {
|
|
343
|
+
view,
|
|
344
|
+
data,
|
|
345
|
+
getItemId,
|
|
346
|
+
selection,
|
|
347
|
+
paginationInfo: defaultPaginationInfo,
|
|
348
|
+
} ),
|
|
349
|
+
{
|
|
350
|
+
initialProps: {
|
|
351
|
+
view: initialView,
|
|
352
|
+
data: initialData,
|
|
353
|
+
selection: [ '5' ],
|
|
354
|
+
},
|
|
355
|
+
}
|
|
356
|
+
);
|
|
357
|
+
|
|
358
|
+
act( () => {
|
|
359
|
+
result.current.setVisibleEntries?.( [ 50, 51 ] );
|
|
360
|
+
} );
|
|
361
|
+
|
|
362
|
+
const newData: TestItem[] = Array.from(
|
|
363
|
+
{ length: 10 },
|
|
364
|
+
( _, i ) => ( { id: 31 + i } )
|
|
365
|
+
);
|
|
366
|
+
const newView = { ...initialView, startPosition: 31 } as View;
|
|
367
|
+
|
|
368
|
+
rerender( {
|
|
369
|
+
view: newView,
|
|
370
|
+
data: newData,
|
|
371
|
+
selection: [ '5' ],
|
|
372
|
+
} );
|
|
373
|
+
|
|
374
|
+
expect(
|
|
375
|
+
result.current.data.some(
|
|
376
|
+
( item: TestItem & { position?: number } ) =>
|
|
377
|
+
item.id === 5
|
|
378
|
+
)
|
|
379
|
+
).toBe( true );
|
|
380
|
+
} );
|
|
381
|
+
|
|
382
|
+
it( 'keeps items within buffer range of visible entries', () => {
|
|
383
|
+
// Create a large dataset
|
|
384
|
+
const initialData: TestItem[] = Array.from(
|
|
385
|
+
{ length: 30 },
|
|
386
|
+
( _, i ) => ( { id: i + 1 } )
|
|
387
|
+
);
|
|
388
|
+
const initialView = {
|
|
389
|
+
type: 'table',
|
|
390
|
+
infiniteScrollEnabled: true,
|
|
391
|
+
startPosition: 1,
|
|
392
|
+
} as View;
|
|
393
|
+
|
|
394
|
+
const { result, rerender } = renderHook(
|
|
395
|
+
( { view, data } ) =>
|
|
396
|
+
useData( {
|
|
397
|
+
view,
|
|
398
|
+
data,
|
|
399
|
+
getItemId,
|
|
400
|
+
paginationInfo: defaultPaginationInfo,
|
|
401
|
+
} ),
|
|
402
|
+
{ initialProps: { view: initialView, data: initialData } }
|
|
403
|
+
);
|
|
404
|
+
|
|
405
|
+
expect( result.current.data ).toHaveLength( 30 );
|
|
406
|
+
|
|
407
|
+
// Set visible entries to middle of the list
|
|
408
|
+
act( () => {
|
|
409
|
+
result.current.setVisibleEntries?.( [ 15, 16, 17, 18 ] );
|
|
410
|
+
} );
|
|
411
|
+
|
|
412
|
+
// Scroll down with new data to trigger buffer logic
|
|
413
|
+
const newData: TestItem[] = Array.from(
|
|
414
|
+
{ length: 10 },
|
|
415
|
+
( _, i ) => ( { id: 31 + i } )
|
|
416
|
+
);
|
|
417
|
+
const newView = { ...initialView, startPosition: 31 } as View;
|
|
418
|
+
|
|
419
|
+
rerender( { view: newView, data: newData } );
|
|
420
|
+
|
|
421
|
+
// Items far above visible range should be trimmed (buffer of 20)
|
|
422
|
+
// Visible min is 15, so items below position (15 - 20 = -5) should be removed
|
|
423
|
+
// Since all items have positive positions, none should be removed in this case
|
|
424
|
+
// when scrolling down
|
|
425
|
+
const positions = result.current.data.map(
|
|
426
|
+
( d: TestItem & { position?: number } ) =>
|
|
427
|
+
( d as TestItem & { position: number } ).position
|
|
428
|
+
);
|
|
429
|
+
const minPosition = Math.min( ...positions );
|
|
430
|
+
|
|
431
|
+
// When scrolling down, items above visible range minus buffer should be trimmed
|
|
432
|
+
// visibleMin - buffer = 15 - 20 = -5, so all items >= -5 are kept
|
|
433
|
+
expect( minPosition ).toBeGreaterThanOrEqual( -5 );
|
|
434
|
+
} );
|
|
435
|
+
|
|
436
|
+
it( 'trims items from the end when scrolling up', () => {
|
|
437
|
+
// Start with items at high positions
|
|
438
|
+
const initialData: TestItem[] = Array.from(
|
|
439
|
+
{ length: 30 },
|
|
440
|
+
( _, i ) => ( { id: i + 50 } )
|
|
441
|
+
);
|
|
442
|
+
const initialView = {
|
|
443
|
+
type: 'table',
|
|
444
|
+
infiniteScrollEnabled: true,
|
|
445
|
+
startPosition: 50,
|
|
446
|
+
} as View;
|
|
447
|
+
|
|
448
|
+
const { result, rerender } = renderHook(
|
|
449
|
+
( { view, data } ) =>
|
|
450
|
+
useData( {
|
|
451
|
+
view,
|
|
452
|
+
data,
|
|
453
|
+
getItemId,
|
|
454
|
+
paginationInfo: defaultPaginationInfo,
|
|
455
|
+
} ),
|
|
456
|
+
{ initialProps: { view: initialView, data: initialData } }
|
|
457
|
+
);
|
|
458
|
+
|
|
459
|
+
// Set visible entries
|
|
460
|
+
act( () => {
|
|
461
|
+
result.current.setVisibleEntries?.( [ 55, 56, 57, 58 ] );
|
|
462
|
+
} );
|
|
463
|
+
|
|
464
|
+
// Scroll up with new data
|
|
465
|
+
const newData: TestItem[] = Array.from(
|
|
466
|
+
{ length: 10 },
|
|
467
|
+
( _, i ) => ( {
|
|
468
|
+
id: i + 40,
|
|
469
|
+
} )
|
|
470
|
+
);
|
|
471
|
+
const newView = { ...initialView, startPosition: 40 } as View;
|
|
472
|
+
|
|
473
|
+
rerender( { view: newView, data: newData } );
|
|
474
|
+
|
|
475
|
+
// When scrolling up, items below visible range + buffer should be trimmed
|
|
476
|
+
// visibleMax + buffer = 58 + 20 = 78
|
|
477
|
+
const positions = result.current.data.map(
|
|
478
|
+
( d: TestItem & { position?: number } ) =>
|
|
479
|
+
( d as TestItem & { position: number } ).position
|
|
480
|
+
);
|
|
481
|
+
const maxPosition = Math.max( ...positions );
|
|
482
|
+
|
|
483
|
+
expect( maxPosition ).toBeLessThanOrEqual( 78 );
|
|
484
|
+
} );
|
|
485
|
+
} );
|
|
486
|
+
|
|
487
|
+
describe( 'view changes', () => {
|
|
488
|
+
it( 'resets data when search changes', () => {
|
|
489
|
+
const initialData: TestItem[] = [ { id: 1 }, { id: 2 } ];
|
|
490
|
+
const initialView = {
|
|
491
|
+
type: 'table',
|
|
492
|
+
infiniteScrollEnabled: true,
|
|
493
|
+
startPosition: 1,
|
|
494
|
+
search: '',
|
|
495
|
+
} as View;
|
|
496
|
+
|
|
497
|
+
const { result, rerender } = renderHook(
|
|
498
|
+
( { view, data } ) =>
|
|
499
|
+
useData( {
|
|
500
|
+
view,
|
|
501
|
+
data,
|
|
502
|
+
getItemId,
|
|
503
|
+
paginationInfo: defaultPaginationInfo,
|
|
504
|
+
} ),
|
|
505
|
+
{ initialProps: { view: initialView, data: initialData } }
|
|
506
|
+
);
|
|
507
|
+
|
|
508
|
+
expect( result.current.data ).toHaveLength( 2 );
|
|
509
|
+
|
|
510
|
+
// Change search - data should be replaced, not appended
|
|
511
|
+
const newData: TestItem[] = [ { id: 3 } ];
|
|
512
|
+
const newView = { ...initialView, search: 'test' } as View;
|
|
513
|
+
|
|
514
|
+
rerender( { view: newView, data: newData } );
|
|
515
|
+
|
|
516
|
+
// Data should be reset to just the new search results
|
|
517
|
+
expect( result.current.data ).toHaveLength( 1 );
|
|
518
|
+
expect( result.current.data[ 0 ].id ).toBe( 3 );
|
|
519
|
+
} );
|
|
520
|
+
|
|
521
|
+
it( 'resets data when filters change', () => {
|
|
522
|
+
const initialData: TestItem[] = [ { id: 1 }, { id: 2 } ];
|
|
523
|
+
const initialView = {
|
|
524
|
+
type: 'table',
|
|
525
|
+
infiniteScrollEnabled: true,
|
|
526
|
+
startPosition: 1,
|
|
527
|
+
filters: [],
|
|
528
|
+
} as View;
|
|
529
|
+
|
|
530
|
+
const { result, rerender } = renderHook(
|
|
531
|
+
( { view, data } ) =>
|
|
532
|
+
useData( {
|
|
533
|
+
view,
|
|
534
|
+
data,
|
|
535
|
+
getItemId,
|
|
536
|
+
paginationInfo: defaultPaginationInfo,
|
|
537
|
+
} ),
|
|
538
|
+
{ initialProps: { view: initialView, data: initialData } }
|
|
539
|
+
);
|
|
540
|
+
|
|
541
|
+
expect( result.current.data ).toHaveLength( 2 );
|
|
542
|
+
|
|
543
|
+
// Change filters - data should be replaced
|
|
544
|
+
const newData: TestItem[] = [ { id: 5 } ];
|
|
545
|
+
const newView = {
|
|
546
|
+
...initialView,
|
|
547
|
+
filters: [
|
|
548
|
+
{ field: 'status', operator: 'is', value: 'published' },
|
|
549
|
+
],
|
|
550
|
+
} as View;
|
|
551
|
+
|
|
552
|
+
rerender( { view: newView, data: newData } );
|
|
553
|
+
|
|
554
|
+
expect( result.current.data ).toHaveLength( 1 );
|
|
555
|
+
expect( result.current.data[ 0 ].id ).toBe( 5 );
|
|
556
|
+
} );
|
|
557
|
+
|
|
558
|
+
it( 'resets data when perPage changes', () => {
|
|
559
|
+
const initialData: TestItem[] = [ { id: 1 }, { id: 2 } ];
|
|
560
|
+
const initialView = {
|
|
561
|
+
type: 'table',
|
|
562
|
+
infiniteScrollEnabled: true,
|
|
563
|
+
startPosition: 1,
|
|
564
|
+
perPage: 10,
|
|
565
|
+
} as View;
|
|
566
|
+
|
|
567
|
+
const { result, rerender } = renderHook(
|
|
568
|
+
( { view, data } ) =>
|
|
569
|
+
useData( {
|
|
570
|
+
view,
|
|
571
|
+
data,
|
|
572
|
+
getItemId,
|
|
573
|
+
paginationInfo: defaultPaginationInfo,
|
|
574
|
+
} ),
|
|
575
|
+
{ initialProps: { view: initialView, data: initialData } }
|
|
576
|
+
);
|
|
577
|
+
|
|
578
|
+
expect( result.current.data ).toHaveLength( 2 );
|
|
579
|
+
|
|
580
|
+
// Change perPage - data should be replaced
|
|
581
|
+
const newData: TestItem[] = [
|
|
582
|
+
{ id: 1 },
|
|
583
|
+
{ id: 2 },
|
|
584
|
+
{ id: 3 },
|
|
585
|
+
{ id: 4 },
|
|
586
|
+
{ id: 5 },
|
|
587
|
+
];
|
|
588
|
+
const newView = { ...initialView, perPage: 25 } as View;
|
|
589
|
+
|
|
590
|
+
rerender( { view: newView, data: newData } );
|
|
591
|
+
|
|
592
|
+
expect( result.current.data ).toHaveLength( 5 );
|
|
593
|
+
} );
|
|
594
|
+
|
|
595
|
+
it( 'handles transition from infinite scroll disabled to enabled', () => {
|
|
596
|
+
const data: TestItem[] = [ { id: 1 }, { id: 2 } ];
|
|
597
|
+
const initialView = {
|
|
598
|
+
type: 'table',
|
|
599
|
+
infiniteScrollEnabled: false,
|
|
600
|
+
} as View;
|
|
601
|
+
|
|
602
|
+
const { result, rerender } = renderHook(
|
|
603
|
+
( { view, passedData } ) =>
|
|
604
|
+
useData( {
|
|
605
|
+
view,
|
|
606
|
+
data: passedData,
|
|
607
|
+
getItemId,
|
|
608
|
+
paginationInfo: defaultPaginationInfo,
|
|
609
|
+
} ),
|
|
610
|
+
{ initialProps: { view: initialView, passedData: data } }
|
|
611
|
+
);
|
|
612
|
+
|
|
613
|
+
expect( result.current.setVisibleEntries ).toBeUndefined();
|
|
614
|
+
|
|
615
|
+
// Enable infinite scroll
|
|
616
|
+
const newView = {
|
|
617
|
+
...initialView,
|
|
618
|
+
infiniteScrollEnabled: true,
|
|
619
|
+
startPosition: 1,
|
|
620
|
+
} as View;
|
|
621
|
+
|
|
622
|
+
rerender( { view: newView, passedData: data } );
|
|
623
|
+
|
|
624
|
+
expect( result.current.setVisibleEntries ).toBeDefined();
|
|
625
|
+
expect( result.current.data ).toHaveLength( 2 );
|
|
626
|
+
} );
|
|
627
|
+
|
|
628
|
+
it( 'returns all data when clearing search after filtering', () => {
|
|
629
|
+
// This tests the scenario where:
|
|
630
|
+
// 1. User has full data list
|
|
631
|
+
// 2. User searches and gets fewer results
|
|
632
|
+
// 3. Visible entries are set for the filtered results
|
|
633
|
+
// 4. User clears search
|
|
634
|
+
// 5. Full data should be returned, not limited by stale visible entries
|
|
635
|
+
const fullData: TestItem[] = Array.from(
|
|
636
|
+
{ length: 25 },
|
|
637
|
+
( _, i ) => ( { id: i + 1 } )
|
|
638
|
+
);
|
|
639
|
+
const initialView = {
|
|
640
|
+
type: 'table',
|
|
641
|
+
infiniteScrollEnabled: true,
|
|
642
|
+
startPosition: 1,
|
|
643
|
+
search: '',
|
|
644
|
+
} as View;
|
|
645
|
+
|
|
646
|
+
const { result, rerender } = renderHook(
|
|
647
|
+
( { view, data } ) =>
|
|
648
|
+
useData( {
|
|
649
|
+
view,
|
|
650
|
+
data,
|
|
651
|
+
getItemId,
|
|
652
|
+
paginationInfo: defaultPaginationInfo,
|
|
653
|
+
} ),
|
|
654
|
+
{ initialProps: { view: initialView, data: fullData } }
|
|
655
|
+
);
|
|
656
|
+
|
|
657
|
+
// Simulate visible entries being set for the 6 items
|
|
658
|
+
act( () => {
|
|
659
|
+
result.current.setVisibleEntries?.( [ 1, 2, 3, 4, 5, 6 ] );
|
|
660
|
+
} );
|
|
661
|
+
const clearedView = { ...initialView, search: '' } as View;
|
|
662
|
+
rerender( { view: clearedView, data: fullData } );
|
|
663
|
+
|
|
664
|
+
// Should return all 25 items, not limited by stale visible entries
|
|
665
|
+
expect( result.current.data ).toHaveLength( 25 );
|
|
666
|
+
} );
|
|
667
|
+
|
|
668
|
+
it( 'returns all data when changing search term', () => {
|
|
669
|
+
const initialView = {
|
|
670
|
+
type: 'table',
|
|
671
|
+
infiniteScrollEnabled: true,
|
|
672
|
+
startPosition: 1,
|
|
673
|
+
search: 'foo',
|
|
674
|
+
} as View;
|
|
675
|
+
const fooResults: TestItem[] = [
|
|
676
|
+
{ id: 1 },
|
|
677
|
+
{ id: 2 },
|
|
678
|
+
{ id: 3 },
|
|
679
|
+
];
|
|
680
|
+
|
|
681
|
+
const { result, rerender } = renderHook(
|
|
682
|
+
( { view, data } ) =>
|
|
683
|
+
useData( {
|
|
684
|
+
view,
|
|
685
|
+
data,
|
|
686
|
+
getItemId,
|
|
687
|
+
paginationInfo: defaultPaginationInfo,
|
|
688
|
+
} ),
|
|
689
|
+
{ initialProps: { view: initialView, data: fooResults } }
|
|
690
|
+
);
|
|
691
|
+
|
|
692
|
+
expect( result.current.data ).toHaveLength( 3 );
|
|
693
|
+
|
|
694
|
+
// Set visible entries for the 3 items
|
|
695
|
+
act( () => {
|
|
696
|
+
result.current.setVisibleEntries?.( [ 1, 2, 3 ] );
|
|
697
|
+
} );
|
|
698
|
+
|
|
699
|
+
// Change to a different search with more results
|
|
700
|
+
const barResults: TestItem[] = Array.from(
|
|
701
|
+
{ length: 15 },
|
|
702
|
+
( _, i ) => ( { id: i + 10 } )
|
|
703
|
+
);
|
|
704
|
+
const barView = { ...initialView, search: 'bar' } as View;
|
|
705
|
+
rerender( { view: barView, data: barResults } );
|
|
706
|
+
|
|
707
|
+
// Should return all 15 items, not limited to 3
|
|
708
|
+
expect( result.current.data ).toHaveLength( 15 );
|
|
709
|
+
} );
|
|
710
|
+
|
|
711
|
+
it( 'handles single item', () => {
|
|
712
|
+
const data: TestItem[] = [ { id: 1 } ];
|
|
713
|
+
const view = {
|
|
714
|
+
type: 'table',
|
|
715
|
+
infiniteScrollEnabled: true,
|
|
716
|
+
startPosition: 1,
|
|
717
|
+
} as View;
|
|
718
|
+
|
|
719
|
+
const { result } = renderHook( () =>
|
|
720
|
+
useData( {
|
|
721
|
+
view,
|
|
722
|
+
data,
|
|
723
|
+
getItemId,
|
|
724
|
+
paginationInfo: defaultPaginationInfo,
|
|
725
|
+
} )
|
|
726
|
+
);
|
|
727
|
+
|
|
728
|
+
expect( result.current.data ).toHaveLength( 1 );
|
|
729
|
+
expect(
|
|
730
|
+
(
|
|
731
|
+
result.current.data[ 0 ] as TestItem & {
|
|
732
|
+
position: number;
|
|
733
|
+
}
|
|
734
|
+
).position
|
|
735
|
+
).toBe( 1 );
|
|
736
|
+
} );
|
|
737
|
+
|
|
738
|
+
it( 'maintains correct order after multiple scroll direction changes', () => {
|
|
739
|
+
const initialData: TestItem[] = [
|
|
740
|
+
{ id: 5 },
|
|
741
|
+
{ id: 6 },
|
|
742
|
+
{ id: 7 },
|
|
743
|
+
];
|
|
744
|
+
const initialView = {
|
|
745
|
+
type: 'table',
|
|
746
|
+
infiniteScrollEnabled: true,
|
|
747
|
+
startPosition: 5,
|
|
748
|
+
} as View;
|
|
749
|
+
|
|
750
|
+
const { result, rerender } = renderHook(
|
|
751
|
+
( { view, data } ) =>
|
|
752
|
+
useData( {
|
|
753
|
+
view,
|
|
754
|
+
data,
|
|
755
|
+
getItemId,
|
|
756
|
+
paginationInfo: defaultPaginationInfo,
|
|
757
|
+
} ),
|
|
758
|
+
{ initialProps: { view: initialView, data: initialData } }
|
|
759
|
+
);
|
|
760
|
+
|
|
761
|
+
// Scroll down
|
|
762
|
+
rerender( {
|
|
763
|
+
view: { ...initialView, startPosition: 8 } as View,
|
|
764
|
+
data: [ { id: 8 }, { id: 9 } ],
|
|
765
|
+
} );
|
|
766
|
+
|
|
767
|
+
// Scroll up
|
|
768
|
+
rerender( {
|
|
769
|
+
view: { ...initialView, startPosition: 3 } as View,
|
|
770
|
+
data: [ { id: 3 }, { id: 4 } ],
|
|
771
|
+
} );
|
|
772
|
+
|
|
773
|
+
// Scroll down again
|
|
774
|
+
rerender( {
|
|
775
|
+
view: { ...initialView, startPosition: 10 } as View,
|
|
776
|
+
data: [ { id: 10 } ],
|
|
777
|
+
} );
|
|
778
|
+
|
|
779
|
+
// All items should be in ascending order by position
|
|
780
|
+
const positions = result.current.data.map(
|
|
781
|
+
( d: TestItem & { position?: number } ) =>
|
|
782
|
+
( d as TestItem & { position: number } ).position
|
|
783
|
+
);
|
|
784
|
+
const sortedPositions = [ ...positions ].sort(
|
|
785
|
+
( a, b ) => a - b
|
|
786
|
+
);
|
|
787
|
+
expect( positions ).toEqual( sortedPositions );
|
|
788
|
+
} );
|
|
789
|
+
} );
|
|
790
|
+
} );
|
|
791
|
+
} );
|