@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.
Files changed (247) hide show
  1. package/CHANGELOG.md +18 -1
  2. package/README.md +19 -3
  3. package/build/components/dataform-controls/datetime.cjs +8 -4
  4. package/build/components/dataform-controls/datetime.cjs.map +2 -2
  5. package/build/components/dataform-layouts/card/index.cjs +132 -128
  6. package/build/components/dataform-layouts/card/index.cjs.map +3 -3
  7. package/build/components/dataviews-bulk-actions/index.cjs +28 -5
  8. package/build/components/dataviews-bulk-actions/index.cjs.map +2 -2
  9. package/build/components/dataviews-context/index.cjs +2 -2
  10. package/build/components/dataviews-context/index.cjs.map +2 -2
  11. package/build/components/dataviews-footer/index.cjs +2 -3
  12. package/build/components/dataviews-footer/index.cjs.map +2 -2
  13. package/build/components/dataviews-layout/index.cjs +12 -3
  14. package/build/components/dataviews-layout/index.cjs.map +2 -2
  15. package/build/components/dataviews-layouts/grid/composite-grid.cjs +378 -245
  16. package/build/components/dataviews-layouts/grid/composite-grid.cjs.map +2 -2
  17. package/build/components/dataviews-layouts/index.cjs +3 -3
  18. package/build/components/dataviews-layouts/index.cjs.map +3 -3
  19. package/build/components/dataviews-layouts/picker-grid/index.cjs +76 -32
  20. package/build/components/dataviews-layouts/picker-grid/index.cjs.map +2 -2
  21. package/build/components/dataviews-layouts/picker-table/index.cjs +34 -22
  22. package/build/components/dataviews-layouts/picker-table/index.cjs.map +2 -2
  23. package/build/components/dataviews-layouts/table/index.cjs +97 -88
  24. package/build/components/dataviews-layouts/table/index.cjs.map +2 -2
  25. package/build/components/dataviews-layouts/table/{use-is-horizontal-scroll-end.cjs → use-scroll-state.cjs} +29 -33
  26. package/build/components/dataviews-layouts/table/use-scroll-state.cjs.map +7 -0
  27. package/build/components/dataviews-layouts/utils/density-picker.cjs.map +2 -2
  28. package/build/components/dataviews-layouts/utils/grid-config-options.cjs +45 -0
  29. package/build/components/dataviews-layouts/utils/grid-config-options.cjs.map +7 -0
  30. package/build/components/dataviews-layouts/utils/use-infinite-scroll.cjs +62 -0
  31. package/build/components/dataviews-layouts/utils/use-infinite-scroll.cjs.map +7 -0
  32. package/build/components/dataviews-picker-footer/index.cjs +23 -4
  33. package/build/components/dataviews-picker-footer/index.cjs.map +2 -2
  34. package/build/components/dataviews-search/index.cjs +2 -1
  35. package/build/components/dataviews-search/index.cjs.map +2 -2
  36. package/build/components/dataviews-selection-checkbox/index.cjs +3 -2
  37. package/build/components/dataviews-selection-checkbox/index.cjs.map +2 -2
  38. package/build/components/dataviews-view-config/index.cjs +0 -2
  39. package/build/components/dataviews-view-config/index.cjs.map +3 -3
  40. package/build/components/dataviews-view-config/infinite-scroll-toggle.cjs +0 -3
  41. package/build/components/dataviews-view-config/infinite-scroll-toggle.cjs.map +2 -2
  42. package/build/dataviews/index.cjs +38 -34
  43. package/build/dataviews/index.cjs.map +3 -3
  44. package/build/dataviews-picker/index.cjs +26 -25
  45. package/build/dataviews-picker/index.cjs.map +3 -3
  46. package/build/hooks/index.cjs +11 -2
  47. package/build/hooks/index.cjs.map +2 -2
  48. package/build/hooks/use-data.cjs +146 -9
  49. package/build/hooks/use-data.cjs.map +2 -2
  50. package/build/hooks/use-infinite-scroll.cjs +208 -0
  51. package/build/hooks/use-infinite-scroll.cjs.map +7 -0
  52. package/build/hooks/use-selected-items.cjs +57 -0
  53. package/build/hooks/use-selected-items.cjs.map +7 -0
  54. package/build/types/dataviews.cjs.map +1 -1
  55. package/build/types/field-api.cjs.map +1 -1
  56. package/build/utils/filter-sort-and-paginate.cjs +5 -1
  57. package/build/utils/filter-sort-and-paginate.cjs.map +2 -2
  58. package/build/utils/get-footer-message.cjs +8 -8
  59. package/build/utils/get-footer-message.cjs.map +2 -2
  60. package/build-module/components/dataform-controls/datetime.mjs +8 -4
  61. package/build-module/components/dataform-controls/datetime.mjs.map +2 -2
  62. package/build-module/components/dataform-layouts/card/index.mjs +132 -133
  63. package/build-module/components/dataform-layouts/card/index.mjs.map +2 -2
  64. package/build-module/components/dataviews-bulk-actions/index.mjs +28 -5
  65. package/build-module/components/dataviews-bulk-actions/index.mjs.map +2 -2
  66. package/build-module/components/dataviews-context/index.mjs +2 -2
  67. package/build-module/components/dataviews-context/index.mjs.map +2 -2
  68. package/build-module/components/dataviews-footer/index.mjs +2 -3
  69. package/build-module/components/dataviews-footer/index.mjs.map +2 -2
  70. package/build-module/components/dataviews-layout/index.mjs +12 -3
  71. package/build-module/components/dataviews-layout/index.mjs.map +2 -2
  72. package/build-module/components/dataviews-layouts/grid/composite-grid.mjs +387 -246
  73. package/build-module/components/dataviews-layouts/grid/composite-grid.mjs.map +2 -2
  74. package/build-module/components/dataviews-layouts/index.mjs +3 -3
  75. package/build-module/components/dataviews-layouts/index.mjs.map +2 -2
  76. package/build-module/components/dataviews-layouts/picker-grid/index.mjs +80 -33
  77. package/build-module/components/dataviews-layouts/picker-grid/index.mjs.map +2 -2
  78. package/build-module/components/dataviews-layouts/picker-table/index.mjs +34 -22
  79. package/build-module/components/dataviews-layouts/picker-table/index.mjs.map +2 -2
  80. package/build-module/components/dataviews-layouts/table/index.mjs +97 -88
  81. package/build-module/components/dataviews-layouts/table/index.mjs.map +2 -2
  82. package/build-module/components/dataviews-layouts/table/use-scroll-state.mjs +46 -0
  83. package/build-module/components/dataviews-layouts/table/use-scroll-state.mjs.map +7 -0
  84. package/build-module/components/dataviews-layouts/utils/density-picker.mjs.map +2 -2
  85. package/build-module/components/dataviews-layouts/utils/grid-config-options.mjs +14 -0
  86. package/build-module/components/dataviews-layouts/utils/grid-config-options.mjs.map +7 -0
  87. package/build-module/components/dataviews-layouts/utils/use-infinite-scroll.mjs +26 -0
  88. package/build-module/components/dataviews-layouts/utils/use-infinite-scroll.mjs.map +7 -0
  89. package/build-module/components/dataviews-picker-footer/index.mjs +23 -4
  90. package/build-module/components/dataviews-picker-footer/index.mjs.map +2 -2
  91. package/build-module/components/dataviews-search/index.mjs +2 -1
  92. package/build-module/components/dataviews-search/index.mjs.map +2 -2
  93. package/build-module/components/dataviews-selection-checkbox/index.mjs +3 -2
  94. package/build-module/components/dataviews-selection-checkbox/index.mjs.map +2 -2
  95. package/build-module/components/dataviews-view-config/index.mjs +0 -2
  96. package/build-module/components/dataviews-view-config/index.mjs.map +2 -2
  97. package/build-module/components/dataviews-view-config/infinite-scroll-toggle.mjs +0 -3
  98. package/build-module/components/dataviews-view-config/infinite-scroll-toggle.mjs.map +2 -2
  99. package/build-module/dataviews/index.mjs +46 -36
  100. package/build-module/dataviews/index.mjs.map +2 -2
  101. package/build-module/dataviews-picker/index.mjs +34 -27
  102. package/build-module/dataviews-picker/index.mjs.map +2 -2
  103. package/build-module/hooks/index.mjs +7 -1
  104. package/build-module/hooks/index.mjs.map +2 -2
  105. package/build-module/hooks/use-data.mjs +147 -10
  106. package/build-module/hooks/use-data.mjs.map +2 -2
  107. package/build-module/hooks/use-infinite-scroll.mjs +188 -0
  108. package/build-module/hooks/use-infinite-scroll.mjs.map +7 -0
  109. package/build-module/hooks/use-selected-items.mjs +36 -0
  110. package/build-module/hooks/use-selected-items.mjs.map +7 -0
  111. package/build-module/utils/filter-sort-and-paginate.mjs +5 -1
  112. package/build-module/utils/filter-sort-and-paginate.mjs.map +2 -2
  113. package/build-module/utils/get-footer-message.mjs +8 -8
  114. package/build-module/utils/get-footer-message.mjs.map +2 -2
  115. package/build-style/style-rtl.css +107 -41
  116. package/build-style/style.css +107 -41
  117. package/build-types/components/dataform-controls/datetime.d.ts +1 -1
  118. package/build-types/components/dataform-controls/datetime.d.ts.map +1 -1
  119. package/build-types/components/dataform-layouts/card/index.d.ts.map +1 -1
  120. package/build-types/components/dataviews-bulk-actions/index.d.ts +2 -1
  121. package/build-types/components/dataviews-bulk-actions/index.d.ts.map +1 -1
  122. package/build-types/components/dataviews-context/index.d.ts +1 -1
  123. package/build-types/components/dataviews-context/index.d.ts.map +1 -1
  124. package/build-types/components/dataviews-footer/index.d.ts.map +1 -1
  125. package/build-types/components/dataviews-layout/index.d.ts.map +1 -1
  126. package/build-types/components/dataviews-layouts/grid/composite-grid.d.ts.map +1 -1
  127. package/build-types/components/dataviews-layouts/index.d.ts +3 -3
  128. package/build-types/components/dataviews-layouts/index.d.ts.map +1 -1
  129. package/build-types/components/dataviews-layouts/picker-grid/index.d.ts.map +1 -1
  130. package/build-types/components/dataviews-layouts/picker-table/index.d.ts.map +1 -1
  131. package/build-types/components/dataviews-layouts/table/index.d.ts.map +1 -1
  132. package/build-types/components/dataviews-layouts/table/use-scroll-state.d.ts +25 -0
  133. package/build-types/components/dataviews-layouts/table/use-scroll-state.d.ts.map +1 -0
  134. package/build-types/components/dataviews-layouts/utils/density-picker.d.ts.map +1 -1
  135. package/build-types/components/dataviews-layouts/utils/grid-config-options.d.ts +2 -0
  136. package/build-types/components/dataviews-layouts/utils/grid-config-options.d.ts.map +1 -0
  137. package/build-types/components/dataviews-layouts/utils/use-infinite-scroll.d.ts +22 -0
  138. package/build-types/components/dataviews-layouts/utils/use-infinite-scroll.d.ts.map +1 -0
  139. package/build-types/components/dataviews-picker-footer/index.d.ts.map +1 -1
  140. package/build-types/components/dataviews-search/index.d.ts.map +1 -1
  141. package/build-types/components/dataviews-selection-checkbox/index.d.ts.map +1 -1
  142. package/build-types/components/dataviews-view-config/index.d.ts.map +1 -1
  143. package/build-types/components/dataviews-view-config/infinite-scroll-toggle.d.ts +1 -1
  144. package/build-types/components/dataviews-view-config/infinite-scroll-toggle.d.ts.map +1 -1
  145. package/build-types/dataviews/index.d.ts +0 -1
  146. package/build-types/dataviews/index.d.ts.map +1 -1
  147. package/build-types/dataviews/stories/empty.d.ts +1 -2
  148. package/build-types/dataviews/stories/empty.d.ts.map +1 -1
  149. package/build-types/dataviews/stories/fixtures.d.ts.map +1 -1
  150. package/build-types/dataviews/stories/free-composition.d.ts.map +1 -1
  151. package/build-types/dataviews/stories/index.story.d.ts +18 -10
  152. package/build-types/dataviews/stories/index.story.d.ts.map +1 -1
  153. package/build-types/dataviews/stories/infinite-scroll.d.ts.map +1 -1
  154. package/build-types/dataviews/stories/layout-activity.d.ts.map +1 -1
  155. package/build-types/dataviews/stories/layout-custom.d.ts +3 -1
  156. package/build-types/dataviews/stories/layout-custom.d.ts.map +1 -1
  157. package/build-types/dataviews/stories/layout-grid.d.ts.map +1 -1
  158. package/build-types/dataviews/stories/layout-list.d.ts.map +1 -1
  159. package/build-types/dataviews/stories/layout-table.d.ts.map +1 -1
  160. package/build-types/dataviews/stories/with-card.d.ts +3 -1
  161. package/build-types/dataviews/stories/with-card.d.ts.map +1 -1
  162. package/build-types/dataviews-picker/index.d.ts +0 -1
  163. package/build-types/dataviews-picker/index.d.ts.map +1 -1
  164. package/build-types/dataviews-picker/stories/fixtures.d.ts.map +1 -1
  165. package/build-types/dataviews-picker/stories/index.story.d.ts.map +1 -1
  166. package/build-types/field-types/stories/index.story.d.ts.map +1 -1
  167. package/build-types/hooks/index.d.ts +3 -0
  168. package/build-types/hooks/index.d.ts.map +1 -1
  169. package/build-types/hooks/test/use-data.d.ts +2 -0
  170. package/build-types/hooks/test/use-data.d.ts.map +1 -0
  171. package/build-types/hooks/use-data.d.ts +41 -3
  172. package/build-types/hooks/use-data.d.ts.map +1 -1
  173. package/build-types/hooks/use-infinite-scroll.d.ts +21 -0
  174. package/build-types/hooks/use-infinite-scroll.d.ts.map +1 -0
  175. package/build-types/hooks/use-selected-items.d.ts +19 -0
  176. package/build-types/hooks/use-selected-items.d.ts.map +1 -0
  177. package/build-types/types/dataviews.d.ts +15 -1
  178. package/build-types/types/dataviews.d.ts.map +1 -1
  179. package/build-types/types/field-api.d.ts +15 -4
  180. package/build-types/types/field-api.d.ts.map +1 -1
  181. package/build-types/utils/filter-sort-and-paginate.d.ts.map +1 -1
  182. package/build-types/utils/get-footer-message.d.ts +3 -2
  183. package/build-types/utils/get-footer-message.d.ts.map +1 -1
  184. package/build-wp/index.js +3202 -2761
  185. package/package.json +19 -19
  186. package/src/components/dataform-controls/datetime.tsx +19 -11
  187. package/src/components/dataform-layouts/card/index.tsx +171 -146
  188. package/src/components/dataform-layouts/card/style.scss +8 -5
  189. package/src/components/dataviews-bulk-actions/index.tsx +28 -1
  190. package/src/components/dataviews-context/index.ts +2 -2
  191. package/src/components/dataviews-footer/index.tsx +1 -6
  192. package/src/components/dataviews-layout/index.tsx +41 -19
  193. package/src/components/dataviews-layout/style.scss +8 -0
  194. package/src/components/dataviews-layouts/grid/composite-grid.tsx +433 -278
  195. package/src/components/dataviews-layouts/grid/style.scss +22 -2
  196. package/src/components/dataviews-layouts/index.ts +3 -3
  197. package/src/components/dataviews-layouts/picker-grid/index.tsx +70 -17
  198. package/src/components/dataviews-layouts/picker-grid/style.scss +10 -0
  199. package/src/components/dataviews-layouts/picker-table/index.tsx +42 -22
  200. package/src/components/dataviews-layouts/table/index.tsx +10 -4
  201. package/src/components/dataviews-layouts/table/style.scss +13 -0
  202. package/src/components/dataviews-layouts/table/use-scroll-state.ts +79 -0
  203. package/src/components/dataviews-layouts/utils/density-picker.tsx +12 -2
  204. package/src/components/dataviews-layouts/utils/grid-config-options.tsx +14 -0
  205. package/src/components/dataviews-layouts/utils/grid-items.scss +9 -1
  206. package/src/components/dataviews-layouts/utils/use-infinite-scroll.ts +64 -0
  207. package/src/components/dataviews-picker-footer/index.tsx +21 -1
  208. package/src/components/dataviews-search/index.tsx +2 -1
  209. package/src/components/dataviews-selection-checkbox/index.tsx +4 -2
  210. package/src/components/dataviews-view-config/index.tsx +0 -2
  211. package/src/components/dataviews-view-config/infinite-scroll-toggle.tsx +0 -5
  212. package/src/dataviews/index.tsx +58 -45
  213. package/src/dataviews/stories/empty.tsx +1 -3
  214. package/src/dataviews/stories/fixtures.tsx +288 -0
  215. package/src/dataviews/stories/free-composition.tsx +44 -45
  216. package/src/dataviews/stories/index.story.tsx +31 -8
  217. package/src/dataviews/stories/infinite-scroll.tsx +7 -93
  218. package/src/dataviews/stories/layout-activity.tsx +1 -0
  219. package/src/dataviews/stories/layout-custom.tsx +7 -3
  220. package/src/dataviews/stories/layout-grid.tsx +1 -0
  221. package/src/dataviews/stories/layout-list.tsx +1 -0
  222. package/src/dataviews/stories/layout-table.tsx +1 -0
  223. package/src/dataviews/stories/style.css +0 -5
  224. package/src/dataviews/stories/with-card.tsx +35 -24
  225. package/src/dataviews/style.scss +5 -8
  226. package/src/dataviews/test/dataviews.tsx +54 -1
  227. package/src/dataviews-picker/index.tsx +41 -35
  228. package/src/dataviews-picker/stories/fixtures.tsx +270 -0
  229. package/src/dataviews-picker/stories/index.story.tsx +62 -129
  230. package/src/field-types/stories/index.story.tsx +12 -0
  231. package/src/hooks/index.ts +3 -0
  232. package/src/hooks/test/use-data.ts +791 -0
  233. package/src/hooks/use-data.ts +288 -21
  234. package/src/hooks/use-infinite-scroll.ts +304 -0
  235. package/src/hooks/use-selected-items.ts +72 -0
  236. package/src/style.scss +1 -0
  237. package/src/types/dataviews.ts +18 -1
  238. package/src/types/field-api.ts +16 -3
  239. package/src/utils/filter-sort-and-paginate.ts +13 -1
  240. package/src/utils/get-footer-message.ts +12 -9
  241. package/src/utils/test/filter-sort-and-paginate.js +78 -54
  242. package/build/components/dataviews-layouts/table/use-is-horizontal-scroll-end.cjs.map +0 -7
  243. package/build-module/components/dataviews-layouts/table/use-is-horizontal-scroll-end.mjs +0 -50
  244. package/build-module/components/dataviews-layouts/table/use-is-horizontal-scroll-end.mjs.map +0 -7
  245. package/build-types/components/dataviews-layouts/table/use-is-horizontal-scroll-end.d.ts +0 -19
  246. package/build-types/components/dataviews-layouts/table/use-is-horizontal-scroll-end.d.ts.map +0 -1
  247. package/src/components/dataviews-layouts/table/use-is-horizontal-scroll-end.ts +0 -82
@@ -32,15 +32,32 @@ function BulkSelectionCheckbox< Item >( {
32
32
  onChangeSelection,
33
33
  data,
34
34
  getItemId,
35
+ disableSelectAll = false,
35
36
  }: {
36
37
  selection: string[];
37
38
  selectedItems: Item[];
38
39
  onChangeSelection: SetSelection;
39
40
  data: Item[];
40
41
  getItemId: ( item: Item ) => string;
42
+ disableSelectAll?: boolean;
41
43
  } ) {
44
+ const hasSelection = selection.length > 0;
42
45
  const areAllSelected = selectedItems.length === data.length;
43
46
 
47
+ if ( disableSelectAll ) {
48
+ return (
49
+ <CheckboxControl
50
+ className="dataviews-view-table-selection-checkbox"
51
+ checked={ hasSelection }
52
+ disabled={ ! hasSelection }
53
+ onChange={ () => {
54
+ onChangeSelection( [] );
55
+ } }
56
+ aria-label={ __( 'Deselect all' ) }
57
+ />
58
+ );
59
+ }
60
+
44
61
  return (
45
62
  <CheckboxControl
46
63
  className="dataviews-view-table-selection-checkbox"
@@ -136,6 +153,7 @@ export function DataViewsPickerFooter() {
136
153
  getItemId,
137
154
  actions = EMPTY_ARRAY,
138
155
  paginationInfo,
156
+ view,
139
157
  } = useContext( DataViewsContext );
140
158
 
141
159
  const isMultiselect = useIsMultiselectPicker( actions );
@@ -143,7 +161,8 @@ export function DataViewsPickerFooter() {
143
161
  const message = getFooterMessage(
144
162
  selection.length,
145
163
  data.length,
146
- paginationInfo.totalItems
164
+ paginationInfo.totalItems,
165
+ !! view.infiniteScrollEnabled
147
166
  );
148
167
 
149
168
  const selectedItems = useMemo(
@@ -173,6 +192,7 @@ export function DataViewsPickerFooter() {
173
192
  onChangeSelection={ onChangeSelection }
174
193
  data={ data }
175
194
  getItemId={ getItemId }
195
+ disableSelectAll={ !! view.infiniteScrollEnabled }
176
196
  />
177
197
  ) }
178
198
  <span className="dataviews-bulk-actions-footer__item-count">
@@ -35,7 +35,8 @@ const DataViewsSearch = memo( function Search( { label }: SearchProps ) {
35
35
  if ( debouncedSearch !== viewRef.current?.search ) {
36
36
  onChangeViewRef.current( {
37
37
  ...viewRef.current,
38
- page: 1,
38
+ page: view.page ? 1 : undefined,
39
+ startPosition: view.startPosition ? 1 : undefined,
39
40
  search: debouncedSearch,
40
41
  } );
41
42
  }
@@ -30,7 +30,8 @@ export default function DataViewsSelectionCheckbox< Item >( {
30
30
  ...extraProps
31
31
  }: DataViewsSelectionCheckboxProps< Item > ) {
32
32
  const id = getItemId( item );
33
- const checked = ! disabled && selection.includes( id );
33
+ const isInSelectionArray = selection.includes( id );
34
+ const checked = ! disabled && isInSelectionArray;
34
35
 
35
36
  // Fallback label to ensure accessibility
36
37
  const selectionLabel =
@@ -47,8 +48,9 @@ export default function DataViewsSelectionCheckbox< Item >( {
47
48
  return;
48
49
  }
49
50
 
51
+ // Toggle in/out of selection array
50
52
  onChangeSelection(
51
- selection.includes( id )
53
+ isInSelectionArray
52
54
  ? selection.filter( ( itemId ) => id !== itemId )
53
55
  : [ ...selection, id ]
54
56
  );
@@ -31,7 +31,6 @@ import { SORTING_DIRECTIONS, sortIcons, sortLabels } from '../../constants';
31
31
  import { VIEW_LAYOUTS } from '../dataviews-layouts';
32
32
  import type { View } from '../../types';
33
33
  import DataViewsContext from '../dataviews-context';
34
- import InfiniteScrollToggle from './infinite-scroll-toggle';
35
34
  import { PropertiesSection } from './properties-section';
36
35
  import { unlock } from '../../lock-unlock';
37
36
 
@@ -346,7 +345,6 @@ export function DataviewsViewConfigDropdown() {
346
345
  { !! activeLayout?.viewConfigOptions && (
347
346
  <activeLayout.viewConfigOptions />
348
347
  ) }
349
- <InfiniteScrollToggle />
350
348
  <ItemsPerPageControl />
351
349
  <PropertiesSection />
352
350
  </Stack>
@@ -15,11 +15,6 @@ export default function InfiniteScrollToggle() {
15
15
  const { view, onChangeView } = context;
16
16
  const infiniteScrollEnabled = view.infiniteScrollEnabled ?? false;
17
17
 
18
- // Only render the toggle if an infinite scroll handler is available
19
- if ( ! context.hasInfiniteScrollHandler ) {
20
- return null;
21
- }
22
-
23
18
  return (
24
19
  <ToggleControl
25
20
  label={ __( 'Enable infinite scroll' ) }
@@ -2,12 +2,19 @@
2
2
  * External dependencies
3
3
  */
4
4
  import type { ReactNode, ComponentProps, ReactElement } from 'react';
5
+ import clsx from 'clsx';
5
6
 
6
7
  /**
7
8
  * WordPress dependencies
8
9
  */
9
- import { useEffect, useMemo, useRef, useState } from '@wordpress/element';
10
- import { useResizeObserver, throttle } from '@wordpress/compose';
10
+ import {
11
+ useContext,
12
+ useEffect,
13
+ useMemo,
14
+ useRef,
15
+ useState,
16
+ } from '@wordpress/element';
17
+ import { useResizeObserver } from '@wordpress/compose';
11
18
  import { Stack } from '@wordpress/ui';
12
19
 
13
20
  /**
@@ -32,6 +39,7 @@ import DataViewsViewConfig, {
32
39
  } from '../components/dataviews-view-config';
33
40
  import normalizeFields from '../field-types';
34
41
  import useData from '../hooks/use-data';
42
+ import { useInfiniteScroll } from '../hooks/use-infinite-scroll';
35
43
  import type { Action, Field, View, SupportedLayouts } from '../types';
36
44
  import type { SelectionOrUpdater } from '../types/private';
37
45
  type ItemWithId = { id: string };
@@ -48,7 +56,6 @@ type DataViewsProps< Item > = {
48
56
  paginationInfo: {
49
57
  totalItems: number;
50
58
  totalPages: number;
51
- infiniteScrollHandler?: () => void;
52
59
  };
53
60
  defaultLayouts: SupportedLayouts;
54
61
  selection?: string[];
@@ -90,13 +97,18 @@ function DefaultUI( {
90
97
  search = true,
91
98
  searchLabel = undefined,
92
99
  }: DefaultUIProps ) {
100
+ const { view } = useContext( DataViewsContext );
101
+ const isInfiniteScroll = view.infiniteScrollEnabled;
93
102
  return (
94
103
  <>
95
104
  <Stack
96
105
  direction="row"
97
106
  align="top"
98
107
  justify="space-between"
99
- className="dataviews__view-actions"
108
+ className={ clsx( 'dataviews__view-actions', {
109
+ 'dataviews__view-actions--infinite-scroll':
110
+ isInfiniteScroll,
111
+ } ) }
100
112
  gap="xs"
101
113
  >
102
114
  <Stack
@@ -144,7 +156,31 @@ function DataViews< Item >( {
144
156
  empty,
145
157
  onReset,
146
158
  }: DataViewsProps< Item > ) {
147
- const { infiniteScrollHandler } = paginationInfo;
159
+ const [ selectionState, setSelectionState ] = useState< string[] >( [] );
160
+ const isUncontrolled =
161
+ selectionProperty === undefined || onChangeSelection === undefined;
162
+ const selection = isUncontrolled ? selectionState : selectionProperty;
163
+
164
+ // useData handles both infinite scroll and standard pagination paths,
165
+ // preserving previous data while loading and tracking initial load state.
166
+ const {
167
+ data: displayData,
168
+ paginationInfo: displayPaginationInfo,
169
+ hasInitiallyLoaded,
170
+ setVisibleEntries,
171
+ } = useData( {
172
+ view,
173
+ data: data as any,
174
+ getItemId: getItemId as any,
175
+ isLoading,
176
+ selection,
177
+ paginationInfo,
178
+ } ) as {
179
+ data: ( Item & { position?: number } )[];
180
+ paginationInfo: { totalItems: number; totalPages: number };
181
+ hasInitiallyLoaded: boolean;
182
+ setVisibleEntries?: React.Dispatch< React.SetStateAction< number[] > >;
183
+ };
148
184
  const containerRef = useRef< HTMLDivElement >( null );
149
185
  const [ containerWidth, setContainerWidth ] = useState( 0 );
150
186
  const resizeObserverRef = useResizeObserver(
@@ -155,10 +191,6 @@ function DataViews< Item >( {
155
191
  },
156
192
  { box: 'border-box' }
157
193
  );
158
- const [ selectionState, setSelectionState ] = useState< string[] >( [] );
159
- const isUncontrolled =
160
- selectionProperty === undefined || onChangeSelection === undefined;
161
- const selection = isUncontrolled ? selectionState : selectionProperty;
162
194
  const [ openedFilter, setOpenedFilter ] = useState< string | null >( null );
163
195
  function setSelectionWithChange( value: SelectionOrUpdater ) {
164
196
  const newValue =
@@ -171,11 +203,16 @@ function DataViews< Item >( {
171
203
  }
172
204
  }
173
205
  const _fields = useMemo( () => normalizeFields( fields ), [ fields ] );
206
+ // When infinite scroll is enabled, don't filter selection by current data
207
+ // because items may be scrolled out of view but still selected.
174
208
  const _selection = useMemo( () => {
209
+ if ( view.infiniteScrollEnabled ) {
210
+ return selection;
211
+ }
175
212
  return selection.filter( ( id ) =>
176
213
  data.some( ( item ) => getItemId( item ) === id )
177
214
  );
178
- }, [ selection, data, getItemId ] );
215
+ }, [ selection, data, getItemId, view.infiniteScrollEnabled ] );
179
216
 
180
217
  const filters = useFilters( _fields, view );
181
218
  const hasPrimaryOrLockedFilters = useMemo(
@@ -189,39 +226,21 @@ function DataViews< Item >( {
189
226
  hasPrimaryOrLockedFilters
190
227
  );
191
228
 
229
+ const { intersectionObserver } = useInfiniteScroll( {
230
+ view,
231
+ onChangeView,
232
+ isLoading,
233
+ paginationInfo,
234
+ containerRef,
235
+ setVisibleEntries,
236
+ } );
237
+
192
238
  useEffect( () => {
193
239
  if ( hasPrimaryOrLockedFilters && ! isShowingFilter ) {
194
240
  setIsShowingFilter( true );
195
241
  }
196
242
  }, [ hasPrimaryOrLockedFilters, isShowingFilter ] );
197
243
 
198
- // Attach scroll event listener for infinite scroll
199
- useEffect( () => {
200
- if ( ! view.infiniteScrollEnabled || ! containerRef.current ) {
201
- return;
202
- }
203
-
204
- const handleScroll = throttle( ( event: unknown ) => {
205
- const target = ( event as Event ).target as HTMLElement;
206
- const scrollTop = target.scrollTop;
207
- const scrollHeight = target.scrollHeight;
208
- const clientHeight = target.clientHeight;
209
-
210
- // Check if user has scrolled near the bottom
211
- if ( scrollTop + clientHeight >= scrollHeight - 100 ) {
212
- infiniteScrollHandler?.();
213
- }
214
- }, 100 ); // Throttle to 100ms
215
-
216
- const container = containerRef.current;
217
- container.addEventListener( 'scroll', handleScroll );
218
-
219
- return () => {
220
- container.removeEventListener( 'scroll', handleScroll );
221
- handleScroll.cancel(); // Cancel any pending throttled calls
222
- };
223
- }, [ infiniteScrollHandler, view.infiniteScrollEnabled ] );
224
-
225
244
  // Filter out DataViewsPicker layouts.
226
245
  const defaultLayouts = useMemo(
227
246
  () =>
@@ -237,12 +256,6 @@ function DataViews< Item >( {
237
256
  [ defaultLayoutsProperty ]
238
257
  );
239
258
 
240
- const {
241
- data: displayData,
242
- paginationInfo: displayPaginationInfo,
243
- hasInitiallyLoaded,
244
- } = useData( data, isLoading, paginationInfo );
245
-
246
259
  if ( ! defaultLayouts[ view.type ] ) {
247
260
  return null;
248
261
  }
@@ -276,11 +289,11 @@ function DataViews< Item >( {
276
289
  config,
277
290
  empty,
278
291
  hasInitiallyLoaded,
279
- hasInfiniteScrollHandler: !! infiniteScrollHandler,
280
292
  onReset,
293
+ intersectionObserver,
281
294
  } }
282
295
  >
283
- <div className="dataviews-wrapper" ref={ containerRef }>
296
+ <div className="dataviews-wrapper">
284
297
  { children ?? (
285
298
  <DefaultUI
286
299
  header={ header }
@@ -47,11 +47,9 @@ const CustomEmptyComponent = () => (
47
47
 
48
48
  const EmptyComponent = ( {
49
49
  customEmpty,
50
- containerHeight,
51
50
  isLoading,
52
51
  }: {
53
52
  customEmpty?: boolean;
54
- containerHeight?: 'auto' | '50vh' | '100vh';
55
53
  isLoading?: boolean;
56
54
  } ) => {
57
55
  const [ view, setView ] = useState< View >( {
@@ -69,7 +67,7 @@ const EmptyComponent = ( {
69
67
  style={ {
70
68
  display: 'flex',
71
69
  flexDirection: 'column',
72
- height: containerHeight,
70
+ height: '100%',
73
71
  } }
74
72
  >
75
73
  <DataViews
@@ -333,6 +333,294 @@ export const data: SpaceObject[] = [
333
333
  email: 'thessalonikopolymnianebuchodonossarinacharybdis@example.com',
334
334
  author: 'interstellar_nomadic_planetary_body_tracking_specialist',
335
335
  },
336
+ {
337
+ id: 20,
338
+ name: {
339
+ title: 'Titan',
340
+ description: 'Largest moon of Saturn',
341
+ },
342
+ image: 'https://upload.wikimedia.org/wikipedia/commons/f/fe/Titan_in_true_color_by_Kevin_M._Gill.jpg',
343
+ type: 'Satellite',
344
+ isPlanet: false,
345
+ categories: [ 'Solar system', 'Satellite', 'Saturn', 'Moon' ],
346
+ satellites: 0,
347
+ date: '2022-02-15',
348
+ datetime: '2022-02-15T08:30:00Z',
349
+ email: 'titan@example.com',
350
+ author: 'saturn_system_researcher',
351
+ },
352
+ {
353
+ id: 21,
354
+ name: {
355
+ title: 'Enceladus',
356
+ description: 'Icy moon of Saturn with geysers',
357
+ },
358
+ image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/8/83/PIA17202_-_Approaching_Enceladus.jpg/960px-PIA17202_-_Approaching_Enceladus.jpg',
359
+ type: 'Satellite',
360
+ isPlanet: false,
361
+ categories: [ 'Solar system', 'Satellite', 'Saturn', 'Moon' ],
362
+ satellites: 0,
363
+ date: '2023-03-20',
364
+ datetime: '2023-03-20T11:45:00Z',
365
+ email: 'enceladus@example.com',
366
+ author: 'cryovolcanism_observer',
367
+ },
368
+ {
369
+ id: 22,
370
+ name: {
371
+ title: 'Mimas',
372
+ description: 'Death Star moon of Saturn',
373
+ },
374
+ image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Mimas_Cassini.jpg/960px-Mimas_Cassini.jpg',
375
+ type: 'Satellite',
376
+ isPlanet: false,
377
+ categories: [ 'Solar system', 'Satellite', 'Saturn', 'Moon' ],
378
+ satellites: 0,
379
+ date: '2021-07-12',
380
+ datetime: '2021-07-12T15:20:00Z',
381
+ email: 'mimas@example.com',
382
+ author: 'impact_crater_analyst',
383
+ },
384
+ {
385
+ id: 23,
386
+ name: {
387
+ title: 'Charon',
388
+ description: 'Largest moon of Pluto',
389
+ },
390
+ image: 'https://upload.wikimedia.org/wikipedia/commons/2/2e/Charon_in_True_Color_-_High-Res.jpg',
391
+ type: 'Satellite',
392
+ isPlanet: false,
393
+ categories: [ 'Solar system', 'Satellite', 'Pluto', 'Moon' ],
394
+ satellites: 0,
395
+ date: '2020-09-25',
396
+ datetime: '2020-09-25T13:15:00Z',
397
+ email: 'charon@example.com',
398
+ author: 'pluto_system_mapper',
399
+ },
400
+ {
401
+ id: 24,
402
+ name: {
403
+ title: 'Phobos',
404
+ description: 'Larger moon of Mars',
405
+ },
406
+ image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/5/5c/Phobos_colour_2008.jpg/960px-Phobos_colour_2008.jpg',
407
+ type: 'Satellite',
408
+ isPlanet: false,
409
+ categories: [ 'Solar system', 'Satellite', 'Mars', 'Moon' ],
410
+ satellites: 0,
411
+ date: '2019-06-14',
412
+ datetime: '2019-06-14T07:45:00Z',
413
+ email: 'phobos@example.com',
414
+ author: 'martian_surface_cartographer',
415
+ },
416
+ {
417
+ id: 25,
418
+ name: {
419
+ title: 'Deimos',
420
+ description: 'Smaller moon of Mars',
421
+ },
422
+ image: 'https://upload.wikimedia.org/wikipedia/commons/8/86/NASA-Deimos-MarsMoon-20090221.jpg',
423
+ type: 'Satellite',
424
+ isPlanet: false,
425
+ categories: [ 'Solar system', 'Satellite', 'Mars', 'Moon' ],
426
+ satellites: 0,
427
+ date: '2018-11-30',
428
+ datetime: '2018-11-30T16:00:00Z',
429
+ email: 'deimos@example.com',
430
+ author: 'small_moon_surveyor',
431
+ },
432
+ {
433
+ id: 26,
434
+ name: {
435
+ title: 'Rhea',
436
+ description: 'Second largest moon of Saturn',
437
+ },
438
+ image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/ab/PIA07763_Rhea_full_globe5.jpg/2560px-PIA07763_Rhea_full_globe5.jpg',
439
+ type: 'Satellite',
440
+ isPlanet: false,
441
+ categories: [ 'Solar system', 'Satellite', 'Saturn', 'Moon' ],
442
+ satellites: 0,
443
+ date: '2022-08-19',
444
+ datetime: '2022-08-19T10:30:00Z',
445
+ email: 'rhea@example.com',
446
+ author: 'saturn_geology_specialist',
447
+ },
448
+ {
449
+ id: 27,
450
+ name: {
451
+ title: 'Iapetus',
452
+ description: 'Two-toned moon of Saturn',
453
+ },
454
+ image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/ad/Iapetus_trailing_natural_color.jpg/2560px-Iapetus_trailing_natural_color.jpg',
455
+ type: 'Satellite',
456
+ isPlanet: false,
457
+ categories: [ 'Solar system', 'Satellite', 'Saturn', 'Moon' ],
458
+ satellites: 0,
459
+ date: '2023-01-22',
460
+ datetime: '2023-01-22T14:20:00Z',
461
+ email: 'iapetus@example.com',
462
+ author: 'two_tone_surface_expert',
463
+ },
464
+ {
465
+ id: 28,
466
+ name: {
467
+ title: 'Dione',
468
+ description: 'Icy moon of Saturn',
469
+ },
470
+ image: 'https://upload.wikimedia.org/wikipedia/commons/d/d0/Dione_in_natural_light_%28cropped%29.jpg',
471
+ type: 'Satellite',
472
+ isPlanet: false,
473
+ categories: [ 'Solar system', 'Satellite', 'Saturn', 'Moon' ],
474
+ satellites: 0,
475
+ date: '2021-04-17',
476
+ datetime: '2021-04-17T12:00:00Z',
477
+ email: 'dione@example.com',
478
+ author: 'icy_surface_geochemist',
479
+ },
480
+ {
481
+ id: 29,
482
+ name: {
483
+ title: 'Tethys',
484
+ description: 'Mid-sized moon of Saturn',
485
+ },
486
+ image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/8/87/Tethys_-_Rev_15_%2837267740632%29.png/960px-Tethys_-_Rev_15_%2837267740632%29.png',
487
+ type: 'Satellite',
488
+ isPlanet: false,
489
+ categories: [ 'Solar system', 'Satellite', 'Saturn', 'Moon' ],
490
+ satellites: 0,
491
+ date: '2020-12-05',
492
+ datetime: '2020-12-05T09:40:00Z',
493
+ email: 'tethys@example.com',
494
+ author: 'middle_satellite_researcher',
495
+ },
496
+ {
497
+ id: 30,
498
+ name: {
499
+ title: 'Miranda',
500
+ description: 'Unusual moon of Uranus',
501
+ },
502
+ image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/c/c2/Miranda_mosaic_in_color_-_Voyager_2.png/960px-Miranda_mosaic_in_color_-_Voyager_2.png',
503
+ type: 'Satellite',
504
+ isPlanet: false,
505
+ categories: [ 'Solar system', 'Satellite', 'Uranus', 'Moon' ],
506
+ satellites: 0,
507
+ date: '2024-02-28',
508
+ datetime: '2024-02-28T11:15:00Z',
509
+ email: 'miranda@example.com',
510
+ author: 'uranian_moon_geologist',
511
+ },
512
+ {
513
+ id: 31,
514
+ name: {
515
+ title: 'Ariel',
516
+ description: 'Brightest moon of Uranus',
517
+ },
518
+ image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/8/84/Ariel_in_monochrome.jpg/960px-Ariel_in_monochrome.jpg',
519
+ type: 'Satellite',
520
+ isPlanet: false,
521
+ categories: [ 'Solar system', 'Satellite', 'Uranus', 'Moon' ],
522
+ satellites: 0,
523
+ date: '2023-09-10',
524
+ datetime: '2023-09-10T08:25:00Z',
525
+ email: 'ariel@example.com',
526
+ author: 'planetary_reflectance_specialist',
527
+ },
528
+ {
529
+ id: 32,
530
+ name: {
531
+ title: 'Umbriel',
532
+ description: 'Dark moon of Uranus',
533
+ },
534
+ image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/2/2f/PIA00040_Umbrielx2.47.jpg/560px-PIA00040_Umbrielx2.47.jpg',
535
+ type: 'Satellite',
536
+ isPlanet: false,
537
+ categories: [ 'Solar system', 'Satellite', 'Uranus', 'Moon' ],
538
+ satellites: 0,
539
+ date: '2022-05-03',
540
+ datetime: '2022-05-03T15:50:00Z',
541
+ email: 'umbriel@example.com',
542
+ author: 'dark_surface_researcher',
543
+ },
544
+ {
545
+ id: 33,
546
+ name: {
547
+ title: 'Titania',
548
+ description: 'Largest moon of Uranus',
549
+ },
550
+ image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/d7/Titania_-_Jan_24_1986_%2822689891350%29.jpg/560px-Titania_-_Jan_24_1986_%2822689891350%29.jpg',
551
+ type: 'Satellite',
552
+ isPlanet: false,
553
+ categories: [ 'Solar system', 'Satellite', 'Uranus', 'Moon' ],
554
+ satellites: 0,
555
+ date: '2021-10-18',
556
+ datetime: '2021-10-18T13:35:00Z',
557
+ email: 'titania@example.com',
558
+ author: 'uranian_system_surveyor',
559
+ },
560
+ {
561
+ id: 34,
562
+ name: {
563
+ title: 'Oberon',
564
+ description: 'Outermost major moon of Uranus',
565
+ },
566
+ image: 'https://upload.wikimedia.org/wikipedia/commons/6/6d/Oberon_in_true_color_by_Kevin_M._Gill.jpg',
567
+ type: 'Satellite',
568
+ isPlanet: false,
569
+ categories: [ 'Solar system', 'Satellite', 'Uranus', 'Moon' ],
570
+ satellites: 0,
571
+ date: '2020-07-22',
572
+ datetime: '2020-07-22T10:05:00Z',
573
+ email: 'oberon@example.com',
574
+ author: 'outer_uranian_orbitalist',
575
+ },
576
+ {
577
+ id: 35,
578
+ name: {
579
+ title: 'Ceres',
580
+ description: 'Largest object in the asteroid belt',
581
+ },
582
+ image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/7/76/Ceres_-_RC3_-_Haulani_Crater_%2822381131691%29_%28cropped%29.jpg/560px-Ceres_-_RC3_-_Haulani_Crater_%2822381131691%29_%28cropped%29.jpg',
583
+ type: 'Dwarf planet',
584
+ isPlanet: false,
585
+ categories: [ 'Solar system', 'Dwarf planet', 'Asteroid belt' ],
586
+ satellites: 0,
587
+ date: '2024-08-14',
588
+ datetime: '2024-08-14T16:40:00Z',
589
+ email: 'ceres@example.com',
590
+ author: 'asteroid_belt_specialist',
591
+ },
592
+ {
593
+ id: 36,
594
+ name: {
595
+ title: 'Makemake',
596
+ description: 'Reddish dwarf planet',
597
+ },
598
+ image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/2/29/Makemake_and_its_moon.jpg/560px-Makemake_and_its_moon.jpg',
599
+ type: 'Dwarf planet',
600
+ isPlanet: false,
601
+ categories: [ 'Solar system', 'Dwarf planet', 'Trans-Neptunian' ],
602
+ satellites: 1,
603
+ date: '2022-03-29',
604
+ datetime: '2022-03-29T12:55:00Z',
605
+ email: 'makemake@example.com',
606
+ author: 'trans_neptunian_researcher',
607
+ },
608
+ {
609
+ id: 37,
610
+ name: {
611
+ title: 'Haumea',
612
+ description: 'Elongated dwarf planet',
613
+ },
614
+ image: 'https://upload.wikimedia.org/wikipedia/commons/2/2b/Haumea_Hubble.png',
615
+ type: 'Dwarf planet',
616
+ isPlanet: false,
617
+ categories: [ 'Solar system', 'Dwarf planet', 'Trans-Neptunian' ],
618
+ satellites: 2,
619
+ date: '2021-11-11',
620
+ datetime: '2021-11-11T09:10:00Z',
621
+ email: 'haumea@example.com',
622
+ author: 'dwarf_planet_dynamics_specialist',
623
+ },
336
624
  ];
337
625
 
338
626
  export const actions: Action< SpaceObject >[] = [