@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
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
padding: 0 $grid-unit-30 $grid-unit-30;
|
|
10
10
|
display: flex;
|
|
11
11
|
flex-direction: column;
|
|
12
|
-
gap: $grid-unit-
|
|
12
|
+
gap: $grid-unit-30;
|
|
13
13
|
container-type: inline-size;
|
|
14
14
|
margin-bottom: auto;
|
|
15
15
|
|
|
@@ -17,9 +17,25 @@
|
|
|
17
17
|
transition: padding ease-out 0.1s;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
&.has-compact-density {
|
|
21
|
+
gap: $grid-unit-20;
|
|
22
|
+
|
|
23
|
+
.dataviews-view-grid__row {
|
|
24
|
+
gap: $grid-unit-20;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
&.has-comfortable-density {
|
|
29
|
+
gap: $grid-unit-40;
|
|
30
|
+
|
|
31
|
+
.dataviews-view-grid__row {
|
|
32
|
+
gap: $grid-unit-40;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
20
36
|
.dataviews-view-grid__row {
|
|
21
37
|
display: grid;
|
|
22
|
-
gap: $grid-unit-
|
|
38
|
+
gap: $grid-unit-30;
|
|
23
39
|
|
|
24
40
|
.dataviews-view-grid__row__gridcell {
|
|
25
41
|
border-radius: $radius-medium;
|
|
@@ -41,6 +57,10 @@
|
|
|
41
57
|
}
|
|
42
58
|
}
|
|
43
59
|
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.dataviews-view-grid,
|
|
63
|
+
.dataviews-view-grid-infinite-scroll {
|
|
44
64
|
|
|
45
65
|
.dataviews-view-grid__card {
|
|
46
66
|
height: 100%;
|
|
@@ -27,8 +27,8 @@ import {
|
|
|
27
27
|
LAYOUT_PICKER_GRID,
|
|
28
28
|
LAYOUT_PICKER_TABLE,
|
|
29
29
|
} from '../../constants';
|
|
30
|
-
import PreviewSizePicker from './utils/preview-size-picker';
|
|
31
30
|
import DensityPicker from './utils/density-picker';
|
|
31
|
+
import GridConfigOptions from './utils/grid-config-options';
|
|
32
32
|
|
|
33
33
|
export const VIEW_LAYOUTS = [
|
|
34
34
|
{
|
|
@@ -43,7 +43,7 @@ export const VIEW_LAYOUTS = [
|
|
|
43
43
|
label: __( 'Grid' ),
|
|
44
44
|
component: ViewGrid,
|
|
45
45
|
icon: category,
|
|
46
|
-
viewConfigOptions:
|
|
46
|
+
viewConfigOptions: GridConfigOptions,
|
|
47
47
|
},
|
|
48
48
|
{
|
|
49
49
|
type: LAYOUT_LIST,
|
|
@@ -64,7 +64,7 @@ export const VIEW_LAYOUTS = [
|
|
|
64
64
|
label: __( 'Grid' ),
|
|
65
65
|
component: ViewPickerGrid,
|
|
66
66
|
icon: category,
|
|
67
|
-
viewConfigOptions:
|
|
67
|
+
viewConfigOptions: GridConfigOptions,
|
|
68
68
|
isPicker: true,
|
|
69
69
|
},
|
|
70
70
|
{
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
} from '@wordpress/components';
|
|
17
17
|
import { __, sprintf } from '@wordpress/i18n';
|
|
18
18
|
import { useInstanceId } from '@wordpress/compose';
|
|
19
|
-
import { useContext } from '@wordpress/element';
|
|
19
|
+
import { useContext, useRef } from '@wordpress/element';
|
|
20
20
|
import { Stack } from '@wordpress/ui';
|
|
21
21
|
|
|
22
22
|
/**
|
|
@@ -35,6 +35,11 @@ import type { SetSelection } from '../../../types/private';
|
|
|
35
35
|
import { GridItems } from '../utils/grid-items';
|
|
36
36
|
const { Badge } = unlock( componentsPrivateApis );
|
|
37
37
|
import getDataByGroup from '../utils/get-data-by-group';
|
|
38
|
+
import { useGridColumns } from '../grid/preview-size-picker';
|
|
39
|
+
import {
|
|
40
|
+
useIntersectionObserver,
|
|
41
|
+
usePlaceholdersNeeded,
|
|
42
|
+
} from '../utils/use-infinite-scroll';
|
|
38
43
|
|
|
39
44
|
interface GridItemProps< Item > {
|
|
40
45
|
view: ViewPickerGridType;
|
|
@@ -73,7 +78,16 @@ function GridItem< Item >( {
|
|
|
73
78
|
}: GridItemProps< Item > ) {
|
|
74
79
|
const { showTitle = true, showMedia = true, showDescription = true } = view;
|
|
75
80
|
const id = getItemId( item );
|
|
81
|
+
const elementRef = useRef< HTMLElement | null >( null );
|
|
82
|
+
|
|
76
83
|
const isSelected = selection.includes( id );
|
|
84
|
+
|
|
85
|
+
const setElementRef = ( element: HTMLElement | null ) => {
|
|
86
|
+
elementRef.current = element;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
useIntersectionObserver( elementRef, posinset );
|
|
90
|
+
|
|
77
91
|
const renderedMediaField = mediaField?.render ? (
|
|
78
92
|
<mediaField.render
|
|
79
93
|
item={ item }
|
|
@@ -88,6 +102,7 @@ function GridItem< Item >( {
|
|
|
88
102
|
|
|
89
103
|
return (
|
|
90
104
|
<Composite.Item
|
|
105
|
+
ref={ setElementRef }
|
|
91
106
|
aria-label={
|
|
92
107
|
titleField
|
|
93
108
|
? titleField.getValue( { item } ) || __( '(no title)' )
|
|
@@ -105,6 +120,7 @@ function GridItem< Item >( {
|
|
|
105
120
|
} ) }
|
|
106
121
|
aria-selected={ isSelected }
|
|
107
122
|
onClick={ () => {
|
|
123
|
+
// Toggle in/out of selection array
|
|
108
124
|
if ( isSelected ) {
|
|
109
125
|
onChangeSelection(
|
|
110
126
|
selection.filter( ( itemId ) => id !== itemId )
|
|
@@ -318,12 +334,21 @@ function ViewPickerGrid< Item >( {
|
|
|
318
334
|
: null;
|
|
319
335
|
const dataByGroup = groupField ? getDataByGroup( data, groupField ) : null;
|
|
320
336
|
|
|
321
|
-
const isInfiniteScroll =
|
|
337
|
+
const isInfiniteScroll =
|
|
338
|
+
( view.infiniteScrollEnabled && ! dataByGroup ) ?? false;
|
|
322
339
|
|
|
323
340
|
const currentPage = view?.page ?? 1;
|
|
324
341
|
const perPage = view?.perPage ?? 0;
|
|
325
342
|
const setSize = isInfiniteScroll ? paginationInfo?.totalItems : undefined;
|
|
326
343
|
|
|
344
|
+
// Calculate placeholders needed for infinite scroll
|
|
345
|
+
const gridColumns = useGridColumns();
|
|
346
|
+
const placeholdersNeeded = usePlaceholdersNeeded(
|
|
347
|
+
data,
|
|
348
|
+
isInfiniteScroll,
|
|
349
|
+
gridColumns
|
|
350
|
+
);
|
|
351
|
+
|
|
327
352
|
return (
|
|
328
353
|
<>
|
|
329
354
|
{
|
|
@@ -336,7 +361,14 @@ function ViewPickerGrid< Item >( {
|
|
|
336
361
|
aria-multiselectable={ isMultiselect }
|
|
337
362
|
className={ clsx(
|
|
338
363
|
'dataviews-view-picker-grid',
|
|
339
|
-
className
|
|
364
|
+
className,
|
|
365
|
+
{
|
|
366
|
+
[ `has-${ view.layout?.density }-density` ]:
|
|
367
|
+
view.layout?.density &&
|
|
368
|
+
[ 'compact', 'comfortable' ].includes(
|
|
369
|
+
view.layout.density
|
|
370
|
+
),
|
|
371
|
+
}
|
|
340
372
|
) }
|
|
341
373
|
aria-label={ itemListLabel }
|
|
342
374
|
render={ ( { children, ...props } ) => (
|
|
@@ -371,10 +403,12 @@ function ViewPickerGrid< Item >( {
|
|
|
371
403
|
}
|
|
372
404
|
>
|
|
373
405
|
{ groupItems.map( ( item ) => {
|
|
406
|
+
// Use position from item if available (infinite scroll), otherwise calculate.
|
|
374
407
|
const posInSet =
|
|
408
|
+
( item as any ).position ??
|
|
375
409
|
( currentPage - 1 ) * perPage +
|
|
376
|
-
|
|
377
|
-
|
|
410
|
+
data.indexOf( item ) +
|
|
411
|
+
1;
|
|
378
412
|
return (
|
|
379
413
|
<GridItem
|
|
380
414
|
key={ getItemId( item ) }
|
|
@@ -421,7 +455,15 @@ function ViewPickerGrid< Item >( {
|
|
|
421
455
|
<GridItems
|
|
422
456
|
className={ clsx(
|
|
423
457
|
'dataviews-view-picker-grid',
|
|
424
|
-
className
|
|
458
|
+
className,
|
|
459
|
+
{
|
|
460
|
+
[ `has-${ view.layout?.density }-density` ]:
|
|
461
|
+
view.layout?.density &&
|
|
462
|
+
[
|
|
463
|
+
'compact',
|
|
464
|
+
'comfortable',
|
|
465
|
+
].includes( view.layout.density ),
|
|
466
|
+
}
|
|
425
467
|
) }
|
|
426
468
|
previewSize={ usedPreviewSize }
|
|
427
469
|
aria-busy={ isLoading }
|
|
@@ -436,17 +478,28 @@ function ViewPickerGrid< Item >( {
|
|
|
436
478
|
aria-multiselectable={ isMultiselect }
|
|
437
479
|
aria-label={ itemListLabel }
|
|
438
480
|
>
|
|
439
|
-
{
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
481
|
+
{ /* Render placeholders for unloaded items in first row */ }
|
|
482
|
+
{ Array.from( { length: placeholdersNeeded } ).map(
|
|
483
|
+
( _, index ) => (
|
|
484
|
+
<Composite.Item
|
|
485
|
+
key={ `placeholder-${ index }` }
|
|
486
|
+
render={ ( { children, ...props } ) => (
|
|
487
|
+
<Stack
|
|
488
|
+
direction="column"
|
|
489
|
+
children={ children }
|
|
490
|
+
{ ...props }
|
|
491
|
+
/>
|
|
492
|
+
) }
|
|
493
|
+
role="option"
|
|
494
|
+
aria-hidden
|
|
495
|
+
tabIndex={ -1 }
|
|
496
|
+
className="dataviews-view-picker-grid__card dataviews-view-picker-grid__placeholder"
|
|
497
|
+
/>
|
|
498
|
+
)
|
|
499
|
+
) }
|
|
500
|
+
{ data.map( ( item ) => {
|
|
501
|
+
// Use position from item for accessibility in infinite scroll mode.
|
|
502
|
+
const posinset = ( item as any ).position;
|
|
450
503
|
|
|
451
504
|
return (
|
|
452
505
|
<GridItem
|
|
@@ -5,6 +5,16 @@
|
|
|
5
5
|
@use "../utils/grid-items.scss" as *;
|
|
6
6
|
|
|
7
7
|
.dataviews-view-picker-grid {
|
|
8
|
+
// When grouped, the density class is on the parent Composite,
|
|
9
|
+
// and the gap is on child .dataviews-view-grid-items elements.
|
|
10
|
+
&.has-compact-density .dataviews-view-grid-items {
|
|
11
|
+
gap: $grid-unit-20;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
&.has-comfortable-density .dataviews-view-grid-items {
|
|
15
|
+
gap: $grid-unit-40;
|
|
16
|
+
}
|
|
17
|
+
|
|
8
18
|
.dataviews-view-picker-grid__card {
|
|
9
19
|
height: 100%;
|
|
10
20
|
justify-content: flex-start;
|
|
@@ -33,6 +33,7 @@ import type { SetSelection } from '../../../types/private';
|
|
|
33
33
|
import ColumnHeaderMenu from '../table/column-header-menu';
|
|
34
34
|
import ColumnPrimary from '../table/column-primary';
|
|
35
35
|
import getDataByGroup from '../utils/get-data-by-group';
|
|
36
|
+
import { useIntersectionObserver } from '../utils/use-infinite-scroll';
|
|
36
37
|
|
|
37
38
|
interface TableColumnFieldProps< Item > {
|
|
38
39
|
fields: NormalizedField< Item >[];
|
|
@@ -95,8 +96,17 @@ function TableRow< Item >( {
|
|
|
95
96
|
posinset,
|
|
96
97
|
}: TableRowProps< Item > ) {
|
|
97
98
|
const { paginationInfo } = useContext( DataViewsContext );
|
|
99
|
+
|
|
98
100
|
const isSelected = selection.includes( id );
|
|
101
|
+
|
|
99
102
|
const [ isHovered, setIsHovered ] = useState( false );
|
|
103
|
+
const elementRef = useRef< HTMLElement | null >( null );
|
|
104
|
+
|
|
105
|
+
const setElementRef = ( element: HTMLElement | null ) => {
|
|
106
|
+
elementRef.current = element;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
useIntersectionObserver( elementRef, posinset );
|
|
100
110
|
const {
|
|
101
111
|
showTitle = true,
|
|
102
112
|
showMedia = true,
|
|
@@ -119,6 +129,7 @@ function TableRow< Item >( {
|
|
|
119
129
|
return (
|
|
120
130
|
<Composite.Item
|
|
121
131
|
key={ id }
|
|
132
|
+
ref={ setElementRef }
|
|
122
133
|
render={ ( { children, ...props } ) => (
|
|
123
134
|
<tr
|
|
124
135
|
className={ clsx( 'dataviews-view-table__row', {
|
|
@@ -136,6 +147,7 @@ function TableRow< Item >( {
|
|
|
136
147
|
aria-posinset={ posinset }
|
|
137
148
|
role={ infiniteScrollEnabled ? 'article' : 'option' }
|
|
138
149
|
onClick={ () => {
|
|
150
|
+
// Toggle in/out of selection array
|
|
139
151
|
if ( isSelected ) {
|
|
140
152
|
onChangeSelection(
|
|
141
153
|
selection.filter( ( itemId ) => id !== itemId )
|
|
@@ -236,6 +248,12 @@ function ViewPickerTable< Item >( {
|
|
|
236
248
|
}
|
|
237
249
|
} );
|
|
238
250
|
|
|
251
|
+
const groupField = view.groupBy?.field
|
|
252
|
+
? fields.find( ( f ) => f.id === view.groupBy?.field )
|
|
253
|
+
: null;
|
|
254
|
+
const dataByGroup = groupField ? getDataByGroup( data, groupField ) : null;
|
|
255
|
+
const isInfiniteScroll = view.infiniteScrollEnabled && ! dataByGroup;
|
|
256
|
+
|
|
239
257
|
const tableNoticeId = useId();
|
|
240
258
|
|
|
241
259
|
if ( nextHeaderMenuToFocus ) {
|
|
@@ -264,10 +282,6 @@ function ViewPickerTable< Item >( {
|
|
|
264
282
|
( field ) => field.id === view.descriptionField
|
|
265
283
|
);
|
|
266
284
|
|
|
267
|
-
const groupField = view.groupBy?.field
|
|
268
|
-
? fields.find( ( f ) => f.id === view.groupBy?.field )
|
|
269
|
-
: null;
|
|
270
|
-
const dataByGroup = groupField ? getDataByGroup( data, groupField ) : null;
|
|
271
285
|
const { showTitle = true, showMedia = true, showDescription = true } = view;
|
|
272
286
|
const hasPrimaryColumn =
|
|
273
287
|
( titleField && showTitle ) ||
|
|
@@ -285,7 +299,6 @@ function ViewPickerTable< Item >( {
|
|
|
285
299
|
headerMenuRefs.current.delete( column );
|
|
286
300
|
}
|
|
287
301
|
};
|
|
288
|
-
const isInfiniteScroll = view.infiniteScrollEnabled && ! dataByGroup;
|
|
289
302
|
|
|
290
303
|
return (
|
|
291
304
|
<>
|
|
@@ -319,6 +332,7 @@ function ViewPickerTable< Item >( {
|
|
|
319
332
|
data={ data }
|
|
320
333
|
actions={ actions }
|
|
321
334
|
getItemId={ getItemId }
|
|
335
|
+
disableSelectAll={ isInfiniteScroll }
|
|
322
336
|
/>
|
|
323
337
|
) }
|
|
324
338
|
</th>
|
|
@@ -441,23 +455,29 @@ function ViewPickerTable< Item >( {
|
|
|
441
455
|
orientation="vertical"
|
|
442
456
|
>
|
|
443
457
|
{ hasData &&
|
|
444
|
-
data.map( ( item, index ) =>
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
458
|
+
data.map( ( item, index ) => {
|
|
459
|
+
const itemId = getItemId( item );
|
|
460
|
+
// Use position from item for accessibility in infinite scroll mode.
|
|
461
|
+
const posinset = ( item as any ).position;
|
|
462
|
+
|
|
463
|
+
return (
|
|
464
|
+
<TableRow
|
|
465
|
+
key={ itemId }
|
|
466
|
+
item={ item }
|
|
467
|
+
fields={ fields }
|
|
468
|
+
id={ itemId || index.toString() }
|
|
469
|
+
view={ view }
|
|
470
|
+
titleField={ titleField }
|
|
471
|
+
mediaField={ mediaField }
|
|
472
|
+
descriptionField={ descriptionField }
|
|
473
|
+
selection={ selection }
|
|
474
|
+
getItemId={ getItemId }
|
|
475
|
+
onChangeSelection={ onChangeSelection }
|
|
476
|
+
multiselect={ isMultiselect }
|
|
477
|
+
posinset={ posinset }
|
|
478
|
+
/>
|
|
479
|
+
);
|
|
480
|
+
} ) }
|
|
461
481
|
</Composite>
|
|
462
482
|
) }
|
|
463
483
|
</table>
|
|
@@ -39,7 +39,7 @@ import type {
|
|
|
39
39
|
import type { SetSelection } from '../../../types/private';
|
|
40
40
|
import ColumnHeaderMenu from './column-header-menu';
|
|
41
41
|
import ColumnPrimary from './column-primary';
|
|
42
|
-
import {
|
|
42
|
+
import { useScrollState } from './use-scroll-state';
|
|
43
43
|
import getDataByGroup from '../utils/get-data-by-group';
|
|
44
44
|
import { PropertiesSection } from '../../dataviews-view-config/properties-section';
|
|
45
45
|
import { useDelayedLoading } from '../../../hooks/use-delayed-loading';
|
|
@@ -323,9 +323,9 @@ function ViewTable< Item >( {
|
|
|
323
323
|
|
|
324
324
|
const tableNoticeId = useId();
|
|
325
325
|
|
|
326
|
-
const isHorizontalScrollEnd =
|
|
326
|
+
const { isHorizontalScrollEnd, isVerticallyScrolled } = useScrollState( {
|
|
327
327
|
scrollContainerRef: containerRef,
|
|
328
|
-
|
|
328
|
+
enabledHorizontal: !! actions?.length,
|
|
329
329
|
} );
|
|
330
330
|
|
|
331
331
|
const hasBulkActions = useSomeItemHasAPossibleBulkAction( actions, data );
|
|
@@ -464,7 +464,13 @@ function ViewTable< Item >( {
|
|
|
464
464
|
<PropertiesSection showLabel={ false } />
|
|
465
465
|
</Popover>
|
|
466
466
|
) }
|
|
467
|
-
<thead
|
|
467
|
+
<thead
|
|
468
|
+
className={ clsx( {
|
|
469
|
+
'dataviews-view-table__thead--stuck':
|
|
470
|
+
isVerticallyScrolled,
|
|
471
|
+
} ) }
|
|
472
|
+
onContextMenu={ handleHeaderContextMenu }
|
|
473
|
+
>
|
|
468
474
|
<tr className="dataviews-view-table__row">
|
|
469
475
|
{ hasBulkActions && (
|
|
470
476
|
<th
|
|
@@ -134,6 +134,19 @@
|
|
|
134
134
|
z-index: z-index(".dataviews-view-table thead");
|
|
135
135
|
background-color: inherit;
|
|
136
136
|
|
|
137
|
+
&.dataviews-view-table__thead--stuck {
|
|
138
|
+
&::after {
|
|
139
|
+
display: block;
|
|
140
|
+
content: "";
|
|
141
|
+
position: absolute;
|
|
142
|
+
bottom: 0;
|
|
143
|
+
left: 0;
|
|
144
|
+
right: 0;
|
|
145
|
+
height: 1px;
|
|
146
|
+
background-color: $gray-100;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
137
150
|
tr {
|
|
138
151
|
border: 0;
|
|
139
152
|
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import type { MutableRefObject } from 'react';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* WordPress dependencies
|
|
8
|
+
*/
|
|
9
|
+
import { useCallback, useEffect, useState } from '@wordpress/element';
|
|
10
|
+
import { isRTL } from '@wordpress/i18n';
|
|
11
|
+
|
|
12
|
+
const isScrolledToEnd = ( element: Element ) => {
|
|
13
|
+
if ( isRTL() ) {
|
|
14
|
+
const scrollLeft = Math.abs( element.scrollLeft );
|
|
15
|
+
return scrollLeft <= 1;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return element.scrollLeft + element.clientWidth >= element.scrollWidth - 1;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* A hook to track the scroll state of a container element.
|
|
23
|
+
*
|
|
24
|
+
* Returns whether the container has been scrolled vertically (for sticky header styling)
|
|
25
|
+
* and whether it has reached the horizontal scroll end (for sticky actions column styling).
|
|
26
|
+
*
|
|
27
|
+
* The current way receives "refs" as arguments, but it lacks a mechanism to detect when a ref has changed.
|
|
28
|
+
* As a result, when the "ref" is updated and attached to a new div, the computation should trigger again.
|
|
29
|
+
* However, this isn't possible in the current setup because the hook is unaware that the ref has changed.
|
|
30
|
+
*
|
|
31
|
+
* See https://github.com/Automattic/wp-calypso/pull/103005#discussion_r2077567912.
|
|
32
|
+
*
|
|
33
|
+
* @param {Object} params The parameters for the hook.
|
|
34
|
+
* @param {MutableRefObject<HTMLDivElement | null>} params.scrollContainerRef The ref to the scroll container element.
|
|
35
|
+
* @param {boolean} [params.enabledHorizontal=false] Whether to track horizontal scroll end.
|
|
36
|
+
* @return {{ isHorizontalScrollEnd: boolean, isVerticallyScrolled: boolean }} The scroll state.
|
|
37
|
+
*/
|
|
38
|
+
export function useScrollState( {
|
|
39
|
+
scrollContainerRef,
|
|
40
|
+
enabledHorizontal = false,
|
|
41
|
+
}: {
|
|
42
|
+
scrollContainerRef: React.MutableRefObject< HTMLDivElement | null >;
|
|
43
|
+
enabledHorizontal?: boolean;
|
|
44
|
+
} ): { isHorizontalScrollEnd: boolean; isVerticallyScrolled: boolean } {
|
|
45
|
+
const [ isHorizontalScrollEnd, setIsHorizontalScrollEnd ] =
|
|
46
|
+
useState( false );
|
|
47
|
+
const [ isVerticallyScrolled, setIsVerticallyScrolled ] = useState( false );
|
|
48
|
+
|
|
49
|
+
const handleScroll = useCallback( () => {
|
|
50
|
+
const scrollContainer = scrollContainerRef.current;
|
|
51
|
+
if ( ! scrollContainer ) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if ( enabledHorizontal ) {
|
|
56
|
+
setIsHorizontalScrollEnd( isScrolledToEnd( scrollContainer ) );
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
setIsVerticallyScrolled( scrollContainer.scrollTop > 0 );
|
|
60
|
+
}, [ scrollContainerRef, enabledHorizontal ] );
|
|
61
|
+
useEffect( () => {
|
|
62
|
+
if ( typeof window === 'undefined' || ! scrollContainerRef.current ) {
|
|
63
|
+
return () => {};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const scrollContainer = scrollContainerRef.current;
|
|
67
|
+
|
|
68
|
+
handleScroll();
|
|
69
|
+
scrollContainer.addEventListener( 'scroll', handleScroll );
|
|
70
|
+
window.addEventListener( 'resize', handleScroll );
|
|
71
|
+
|
|
72
|
+
return () => {
|
|
73
|
+
scrollContainer.removeEventListener( 'scroll', handleScroll );
|
|
74
|
+
window.removeEventListener( 'resize', handleScroll );
|
|
75
|
+
};
|
|
76
|
+
}, [ scrollContainerRef, enabledHorizontal, handleScroll ] );
|
|
77
|
+
|
|
78
|
+
return { isHorizontalScrollEnd, isVerticallyScrolled };
|
|
79
|
+
}
|
|
@@ -12,11 +12,21 @@ import { useContext } from '@wordpress/element';
|
|
|
12
12
|
* Internal dependencies
|
|
13
13
|
*/
|
|
14
14
|
import DataViewsContext from '../../dataviews-context';
|
|
15
|
-
import type {
|
|
15
|
+
import type {
|
|
16
|
+
ViewTable,
|
|
17
|
+
ViewList,
|
|
18
|
+
ViewGrid,
|
|
19
|
+
ViewPickerGrid,
|
|
20
|
+
Density,
|
|
21
|
+
} from '../../../types';
|
|
16
22
|
|
|
17
23
|
export default function DensityPicker() {
|
|
18
24
|
const context = useContext( DataViewsContext );
|
|
19
|
-
const view = context.view as
|
|
25
|
+
const view = context.view as
|
|
26
|
+
| ViewTable
|
|
27
|
+
| ViewList
|
|
28
|
+
| ViewGrid
|
|
29
|
+
| ViewPickerGrid;
|
|
20
30
|
return (
|
|
21
31
|
<ToggleGroupControl
|
|
22
32
|
size="__unstable-large"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal dependencies
|
|
3
|
+
*/
|
|
4
|
+
import DensityPicker from './density-picker';
|
|
5
|
+
import PreviewSizePicker from './preview-size-picker';
|
|
6
|
+
|
|
7
|
+
export default function GridConfigOptions() {
|
|
8
|
+
return (
|
|
9
|
+
<>
|
|
10
|
+
<DensityPicker />
|
|
11
|
+
<PreviewSizePicker />
|
|
12
|
+
</>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
.dataviews-view-grid-items {
|
|
4
4
|
margin-bottom: auto;
|
|
5
5
|
display: grid;
|
|
6
|
-
gap: $grid-unit-
|
|
6
|
+
gap: $grid-unit-30;
|
|
7
7
|
grid-template-rows: max-content;
|
|
8
8
|
grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
|
|
9
9
|
padding: 0 $grid-unit-30 $grid-unit-30;
|
|
@@ -12,4 +12,12 @@
|
|
|
12
12
|
@media not (prefers-reduced-motion) {
|
|
13
13
|
transition: padding ease-out 0.1s;
|
|
14
14
|
}
|
|
15
|
+
|
|
16
|
+
&.has-compact-density {
|
|
17
|
+
gap: $grid-unit-20;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
&.has-comfortable-density {
|
|
21
|
+
gap: $grid-unit-40;
|
|
22
|
+
}
|
|
15
23
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { useContext, useEffect } from '@wordpress/element';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Internal dependencies
|
|
8
|
+
*/
|
|
9
|
+
import DataViewsContext from '../../dataviews-context';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Hook to set up an IntersectionObserver for infinite scroll items.
|
|
13
|
+
* Observes the element and triggers the callback when the item becomes visible.
|
|
14
|
+
*
|
|
15
|
+
* @param elementRef - Ref to the DOM element to observe.
|
|
16
|
+
* @param posinset - The position of the item in the set (1-based index).
|
|
17
|
+
*/
|
|
18
|
+
export function useIntersectionObserver(
|
|
19
|
+
elementRef: React.RefObject< HTMLElement | null >,
|
|
20
|
+
posinset: number | undefined
|
|
21
|
+
) {
|
|
22
|
+
const { intersectionObserver } = useContext( DataViewsContext );
|
|
23
|
+
|
|
24
|
+
useEffect( () => {
|
|
25
|
+
const element = elementRef.current;
|
|
26
|
+
if ( ! element || posinset === undefined || ! intersectionObserver ) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
intersectionObserver.observe( element );
|
|
31
|
+
|
|
32
|
+
return () => {
|
|
33
|
+
intersectionObserver.unobserve( element );
|
|
34
|
+
};
|
|
35
|
+
}, [ elementRef, intersectionObserver, posinset ] );
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Hook to calculate the number of placeholder items needed for the first row
|
|
40
|
+
* in an infinite scroll grid layout.
|
|
41
|
+
*
|
|
42
|
+
* When items are loaded starting from a position other than 1, placeholders
|
|
43
|
+
* are needed to maintain proper grid alignment.
|
|
44
|
+
*
|
|
45
|
+
* @param data - The array of data items.
|
|
46
|
+
* @param isInfiniteScroll - Whether infinite scroll is enabled.
|
|
47
|
+
* @param gridColumns - The number of columns in the grid.
|
|
48
|
+
* @return The number of placeholder items needed.
|
|
49
|
+
*/
|
|
50
|
+
export function usePlaceholdersNeeded< Item >(
|
|
51
|
+
data: Item[],
|
|
52
|
+
isInfiniteScroll: boolean,
|
|
53
|
+
gridColumns: number
|
|
54
|
+
): number {
|
|
55
|
+
const hasData = !! data?.length;
|
|
56
|
+
const firstItemPosition =
|
|
57
|
+
hasData && isInfiniteScroll
|
|
58
|
+
? ( data[ 0 ] as { position?: number } ).position
|
|
59
|
+
: undefined;
|
|
60
|
+
|
|
61
|
+
return firstItemPosition && gridColumns
|
|
62
|
+
? ( firstItemPosition - 1 ) % gridColumns
|
|
63
|
+
: 0;
|
|
64
|
+
}
|