@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
@@ -2,12 +2,19 @@
2
2
  * External dependencies
3
3
  */
4
4
  import type { ReactNode } 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
  /**
@@ -30,6 +37,8 @@ import DataViewsViewConfig, {
30
37
  ViewTypeMenu,
31
38
  } from '../components/dataviews-view-config';
32
39
  import normalizeFields from '../field-types';
40
+ import useData from '../hooks/use-data';
41
+ import { useInfiniteScroll } from '../hooks/use-infinite-scroll';
33
42
  import type { ActionButton, Field, View, SupportedLayouts } from '../types';
34
43
  import type { SelectionOrUpdater } from '../types/private';
35
44
  type ItemWithId = { id: string };
@@ -52,7 +61,6 @@ type DataViewsPickerProps< Item > = {
52
61
  paginationInfo: {
53
62
  totalItems: number;
54
63
  totalPages: number;
55
- infiniteScrollHandler?: () => void;
56
64
  };
57
65
  defaultLayouts: SupportedLayouts;
58
66
  selection: string[];
@@ -79,13 +87,18 @@ function DefaultUI( {
79
87
  search = true,
80
88
  searchLabel = undefined,
81
89
  }: DefaultUIProps ) {
90
+ const { view } = useContext( DataViewsContext );
91
+ const isInfiniteScroll = view.infiniteScrollEnabled;
82
92
  return (
83
93
  <>
84
94
  <Stack
85
95
  direction="row"
86
96
  align="top"
87
97
  justify="space-between"
88
- className="dataviews__view-actions"
98
+ className={ clsx( 'dataviews__view-actions', {
99
+ 'dataviews__view-actions--infinite-scroll':
100
+ isInfiniteScroll,
101
+ } ) }
89
102
  gap="xs"
90
103
  >
91
104
  <Stack
@@ -127,7 +140,17 @@ function DataViewsPicker< Item >( {
127
140
  itemListLabel,
128
141
  empty,
129
142
  }: DataViewsPickerProps< Item > ) {
130
- const { infiniteScrollHandler } = paginationInfo;
143
+ // useData ensures data loading is correct whether infinite scroll is enabled or pagination is used.
144
+ const { data: displayData, setVisibleEntries } = useData( {
145
+ view,
146
+ data: data as any,
147
+ getItemId: getItemId as any,
148
+ selection,
149
+ paginationInfo,
150
+ } ) as {
151
+ data: ( Item & { position?: number } )[];
152
+ setVisibleEntries?: React.Dispatch< React.SetStateAction< number[] > >;
153
+ };
131
154
  const containerRef = useRef< HTMLDivElement >( null );
132
155
  const [ containerWidth, setContainerWidth ] = useState( 0 );
133
156
  const resizeObserverRef = useResizeObserver(
@@ -148,6 +171,7 @@ function DataViewsPicker< Item >( {
148
171
  }
149
172
  const _fields = useMemo( () => normalizeFields( fields ), [ fields ] );
150
173
  const filters = useFilters( _fields, view );
174
+
151
175
  const hasPrimaryOrLockedFilters = useMemo(
152
176
  () =>
153
177
  ( filters || [] ).some(
@@ -159,39 +183,21 @@ function DataViewsPicker< Item >( {
159
183
  hasPrimaryOrLockedFilters
160
184
  );
161
185
 
186
+ const { intersectionObserver } = useInfiniteScroll( {
187
+ view,
188
+ onChangeView,
189
+ isLoading,
190
+ paginationInfo,
191
+ containerRef,
192
+ setVisibleEntries,
193
+ } );
194
+
162
195
  useEffect( () => {
163
196
  if ( hasPrimaryOrLockedFilters && ! isShowingFilter ) {
164
197
  setIsShowingFilter( true );
165
198
  }
166
199
  }, [ hasPrimaryOrLockedFilters, isShowingFilter ] );
167
200
 
168
- // Attach scroll event listener for infinite scroll
169
- useEffect( () => {
170
- if ( ! view.infiniteScrollEnabled || ! containerRef.current ) {
171
- return;
172
- }
173
-
174
- const handleScroll = throttle( ( event: unknown ) => {
175
- const target = ( event as Event ).target as HTMLElement;
176
- const scrollTop = target.scrollTop;
177
- const scrollHeight = target.scrollHeight;
178
- const clientHeight = target.clientHeight;
179
-
180
- // Check if user has scrolled near the bottom
181
- if ( scrollTop + clientHeight >= scrollHeight - 100 ) {
182
- infiniteScrollHandler?.();
183
- }
184
- }, 100 ); // Throttle to 100ms
185
-
186
- const container = containerRef.current;
187
- container.addEventListener( 'scroll', handleScroll );
188
-
189
- return () => {
190
- container.removeEventListener( 'scroll', handleScroll );
191
- handleScroll.cancel(); // Cancel any pending throttled calls
192
- };
193
- }, [ infiniteScrollHandler, view.infiniteScrollEnabled ] );
194
-
195
201
  // Filter out DataViewsPicker layouts.
196
202
  const defaultLayouts = useMemo(
197
203
  () =>
@@ -218,7 +224,7 @@ function DataViewsPicker< Item >( {
218
224
  onChangeView,
219
225
  fields: _fields,
220
226
  actions,
221
- data,
227
+ data: displayData,
222
228
  isLoading,
223
229
  paginationInfo,
224
230
  isItemClickable,
@@ -238,10 +244,10 @@ function DataViewsPicker< Item >( {
238
244
  itemListLabel,
239
245
  empty,
240
246
  hasInitiallyLoaded: true,
241
- hasInfiniteScrollHandler: !! infiniteScrollHandler,
247
+ intersectionObserver,
242
248
  } }
243
249
  >
244
- <div className="dataviews-picker-wrapper" ref={ containerRef }>
250
+ <div className="dataviews-picker-wrapper">
245
251
  { children ?? (
246
252
  <DefaultUI search={ search } searchLabel={ searchLabel } />
247
253
  ) }
@@ -312,6 +312,276 @@ export const data: SpaceObject[] = [
312
312
  datetime: '2020-03-01T10:15:20Z',
313
313
  email: 'thessalonikopolymnianebuchodonossarinacharybdis@example.com',
314
314
  },
315
+ {
316
+ id: 20,
317
+ name: {
318
+ title: 'Titan',
319
+ description: 'Largest moon of Saturn',
320
+ },
321
+ image: 'https://upload.wikimedia.org/wikipedia/commons/f/fe/Titan_in_true_color_by_Kevin_M._Gill.jpg',
322
+ type: 'Satellite',
323
+ isPlanet: false,
324
+ categories: [ 'Solar system', 'Satellite', 'Saturn', 'Moon' ],
325
+ satellites: 0,
326
+ date: '2022-02-15',
327
+ datetime: '2022-02-15T08:30:00Z',
328
+ email: 'titan@example.com',
329
+ },
330
+ {
331
+ id: 21,
332
+ name: {
333
+ title: 'Enceladus',
334
+ description: 'Icy moon of Saturn with geysers',
335
+ },
336
+ image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/8/83/PIA17202_-_Approaching_Enceladus.jpg/960px-PIA17202_-_Approaching_Enceladus.jpg',
337
+ type: 'Satellite',
338
+ isPlanet: false,
339
+ categories: [ 'Solar system', 'Satellite', 'Saturn', 'Moon' ],
340
+ satellites: 0,
341
+ date: '2023-03-20',
342
+ datetime: '2023-03-20T11:45:00Z',
343
+ email: 'enceladus@example.com',
344
+ },
345
+ {
346
+ id: 22,
347
+ name: {
348
+ title: 'Mimas',
349
+ description: 'Death Star moon of Saturn',
350
+ },
351
+ image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Mimas_Cassini.jpg/960px-Mimas_Cassini.jpg',
352
+ type: 'Satellite',
353
+ isPlanet: false,
354
+ categories: [ 'Solar system', 'Satellite', 'Saturn', 'Moon' ],
355
+ satellites: 0,
356
+ date: '2021-07-12',
357
+ datetime: '2021-07-12T15:20:00Z',
358
+ email: 'mimas@example.com',
359
+ },
360
+ {
361
+ id: 23,
362
+ name: {
363
+ title: 'Charon',
364
+ description: 'Largest moon of Pluto',
365
+ },
366
+ image: 'https://upload.wikimedia.org/wikipedia/commons/2/2e/Charon_in_True_Color_-_High-Res.jpg',
367
+ type: 'Satellite',
368
+ isPlanet: false,
369
+ categories: [ 'Solar system', 'Satellite', 'Pluto', 'Moon' ],
370
+ satellites: 0,
371
+ date: '2020-09-25',
372
+ datetime: '2020-09-25T13:15:00Z',
373
+ email: 'charon@example.com',
374
+ },
375
+ {
376
+ id: 24,
377
+ name: {
378
+ title: 'Phobos',
379
+ description: 'Larger moon of Mars',
380
+ },
381
+ image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/5/5c/Phobos_colour_2008.jpg/960px-Phobos_colour_2008.jpg',
382
+ type: 'Satellite',
383
+ isPlanet: false,
384
+ categories: [ 'Solar system', 'Satellite', 'Mars', 'Moon' ],
385
+ satellites: 0,
386
+ date: '2019-06-14',
387
+ datetime: '2019-06-14T07:45:00Z',
388
+ email: 'phobos@example.com',
389
+ },
390
+ {
391
+ id: 25,
392
+ name: {
393
+ title: 'Deimos',
394
+ description: 'Smaller moon of Mars',
395
+ },
396
+ image: 'https://upload.wikimedia.org/wikipedia/commons/8/86/NASA-Deimos-MarsMoon-20090221.jpg',
397
+ type: 'Satellite',
398
+ isPlanet: false,
399
+ categories: [ 'Solar system', 'Satellite', 'Mars', 'Moon' ],
400
+ satellites: 0,
401
+ date: '2018-11-30',
402
+ datetime: '2018-11-30T16:00:00Z',
403
+ email: 'deimos@example.com',
404
+ },
405
+ {
406
+ id: 26,
407
+ name: {
408
+ title: 'Rhea',
409
+ description: 'Second largest moon of Saturn',
410
+ },
411
+ image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/ab/PIA07763_Rhea_full_globe5.jpg/2560px-PIA07763_Rhea_full_globe5.jpg',
412
+ type: 'Satellite',
413
+ isPlanet: false,
414
+ categories: [ 'Solar system', 'Satellite', 'Saturn', 'Moon' ],
415
+ satellites: 0,
416
+ date: '2022-08-19',
417
+ datetime: '2022-08-19T10:30:00Z',
418
+ email: 'rhea@example.com',
419
+ },
420
+ {
421
+ id: 27,
422
+ name: {
423
+ title: 'Iapetus',
424
+ description: 'Two-toned moon of Saturn',
425
+ },
426
+ image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/ad/Iapetus_trailing_natural_color.jpg/2560px-Iapetus_trailing_natural_color.jpg',
427
+ type: 'Satellite',
428
+ isPlanet: false,
429
+ categories: [ 'Solar system', 'Satellite', 'Saturn', 'Moon' ],
430
+ satellites: 0,
431
+ date: '2023-01-22',
432
+ datetime: '2023-01-22T14:20:00Z',
433
+ email: 'iapetus@example.com',
434
+ },
435
+ {
436
+ id: 28,
437
+ name: {
438
+ title: 'Dione',
439
+ description: 'Icy moon of Saturn',
440
+ },
441
+ image: 'https://upload.wikimedia.org/wikipedia/commons/d/d0/Dione_in_natural_light_%28cropped%29.jpg',
442
+ type: 'Satellite',
443
+ isPlanet: false,
444
+ categories: [ 'Solar system', 'Satellite', 'Saturn', 'Moon' ],
445
+ satellites: 0,
446
+ date: '2021-04-17',
447
+ datetime: '2021-04-17T12:00:00Z',
448
+ email: 'dione@example.com',
449
+ },
450
+ {
451
+ id: 29,
452
+ name: {
453
+ title: 'Tethys',
454
+ description: 'Mid-sized moon of Saturn',
455
+ },
456
+ image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/8/87/Tethys_-_Rev_15_%2837267740632%29.png/960px-Tethys_-_Rev_15_%2837267740632%29.png',
457
+ type: 'Satellite',
458
+ isPlanet: false,
459
+ categories: [ 'Solar system', 'Satellite', 'Saturn', 'Moon' ],
460
+ satellites: 0,
461
+ date: '2020-12-05',
462
+ datetime: '2020-12-05T09:40:00Z',
463
+ email: 'tethys@example.com',
464
+ },
465
+ {
466
+ id: 30,
467
+ name: {
468
+ title: 'Miranda',
469
+ description: 'Unusual moon of Uranus',
470
+ },
471
+ 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',
472
+ type: 'Satellite',
473
+ isPlanet: false,
474
+ categories: [ 'Solar system', 'Satellite', 'Uranus', 'Moon' ],
475
+ satellites: 0,
476
+ date: '2024-02-28',
477
+ datetime: '2024-02-28T11:15:00Z',
478
+ email: 'miranda@example.com',
479
+ },
480
+ {
481
+ id: 31,
482
+ name: {
483
+ title: 'Ariel',
484
+ description: 'Brightest moon of Uranus',
485
+ },
486
+ image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/8/84/Ariel_in_monochrome.jpg/960px-Ariel_in_monochrome.jpg',
487
+ type: 'Satellite',
488
+ isPlanet: false,
489
+ categories: [ 'Solar system', 'Satellite', 'Uranus', 'Moon' ],
490
+ satellites: 0,
491
+ date: '2023-09-10',
492
+ datetime: '2023-09-10T08:25:00Z',
493
+ email: 'ariel@example.com',
494
+ },
495
+ {
496
+ id: 32,
497
+ name: {
498
+ title: 'Umbriel',
499
+ description: 'Dark moon of Uranus',
500
+ },
501
+ image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/2/2f/PIA00040_Umbrielx2.47.jpg/560px-PIA00040_Umbrielx2.47.jpg',
502
+ type: 'Satellite',
503
+ isPlanet: false,
504
+ categories: [ 'Solar system', 'Satellite', 'Uranus', 'Moon' ],
505
+ satellites: 0,
506
+ date: '2022-05-03',
507
+ datetime: '2022-05-03T15:50:00Z',
508
+ email: 'umbriel@example.com',
509
+ },
510
+ {
511
+ id: 33,
512
+ name: {
513
+ title: 'Titania',
514
+ description: 'Largest moon of Uranus',
515
+ },
516
+ 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',
517
+ type: 'Satellite',
518
+ isPlanet: false,
519
+ categories: [ 'Solar system', 'Satellite', 'Uranus', 'Moon' ],
520
+ satellites: 0,
521
+ date: '2021-10-18',
522
+ datetime: '2021-10-18T13:35:00Z',
523
+ email: 'titania@example.com',
524
+ },
525
+ {
526
+ id: 34,
527
+ name: {
528
+ title: 'Oberon',
529
+ description: 'Outermost major moon of Uranus',
530
+ },
531
+ image: 'https://upload.wikimedia.org/wikipedia/commons/6/6d/Oberon_in_true_color_by_Kevin_M._Gill.jpg',
532
+ type: 'Satellite',
533
+ isPlanet: false,
534
+ categories: [ 'Solar system', 'Satellite', 'Uranus', 'Moon' ],
535
+ satellites: 0,
536
+ date: '2020-07-22',
537
+ datetime: '2020-07-22T10:05:00Z',
538
+ email: 'oberon@example.com',
539
+ },
540
+ {
541
+ id: 35,
542
+ name: {
543
+ title: 'Ceres',
544
+ description: 'Largest object in the asteroid belt',
545
+ },
546
+ 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',
547
+ type: 'Dwarf planet',
548
+ isPlanet: false,
549
+ categories: [ 'Solar system', 'Dwarf planet', 'Asteroid belt' ],
550
+ satellites: 0,
551
+ date: '2024-08-14',
552
+ datetime: '2024-08-14T16:40:00Z',
553
+ email: 'ceres@example.com',
554
+ },
555
+ {
556
+ id: 36,
557
+ name: {
558
+ title: 'Makemake',
559
+ description: 'Reddish dwarf planet',
560
+ },
561
+ image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/2/29/Makemake_and_its_moon.jpg/560px-Makemake_and_its_moon.jpg',
562
+ type: 'Dwarf planet',
563
+ isPlanet: false,
564
+ categories: [ 'Solar system', 'Dwarf planet', 'Trans-Neptunian' ],
565
+ satellites: 1,
566
+ date: '2022-03-29',
567
+ datetime: '2022-03-29T12:55:00Z',
568
+ email: 'makemake@example.com',
569
+ },
570
+ {
571
+ id: 37,
572
+ name: {
573
+ title: 'Haumea',
574
+ description: 'Elongated dwarf planet',
575
+ },
576
+ image: 'https://upload.wikimedia.org/wikipedia/commons/2/2b/Haumea_Hubble.png',
577
+ type: 'Dwarf planet',
578
+ isPlanet: false,
579
+ categories: [ 'Solar system', 'Dwarf planet', 'Trans-Neptunian' ],
580
+ satellites: 2,
581
+ date: '2021-11-11',
582
+ datetime: '2021-11-11T09:10:00Z',
583
+ email: 'haumea@example.com',
584
+ },
315
585
  ];
316
586
 
317
587
  export const fields: Field< SpaceObject >[] = [
@@ -6,7 +6,7 @@ import type { Meta } from '@storybook/react-vite';
6
6
  /**
7
7
  * WordPress dependencies
8
8
  */
9
- import { useState, useMemo, useCallback, useEffect } from '@wordpress/element';
9
+ import { useState, useMemo, useEffect } from '@wordpress/element';
10
10
  import { Modal, Button } from '@wordpress/components';
11
11
  import { Stack } from '@wordpress/ui';
12
12
 
@@ -70,32 +70,66 @@ const DataViewsPickerContent = ( {
70
70
  actions: customActions,
71
71
  selection: customSelection,
72
72
  }: PickerContentProps ) => {
73
- const [ view, setView ] = useState< View >( {
74
- fields: [],
75
- titleField: 'title',
76
- mediaField: 'image',
77
- search: '',
78
- page: 1,
79
- perPage: 10,
80
- filters: [],
81
- type: LAYOUT_PICKER_GRID,
82
- groupBy: isGrouped ? { field: 'type', direction: 'asc' } : undefined,
83
- infiniteScrollEnabled,
73
+ const [ view, setView ] = useState< View >( () => {
74
+ const baseView: View = {
75
+ fields: [],
76
+ titleField: 'title',
77
+ mediaField: 'image',
78
+ search: '',
79
+ filters: [],
80
+ type: LAYOUT_PICKER_GRID,
81
+ groupBy: isGrouped
82
+ ? { field: 'type', direction: 'asc' as const }
83
+ : undefined,
84
+ infiniteScrollEnabled,
85
+ };
86
+
87
+ if ( infiniteScrollEnabled ) {
88
+ return {
89
+ ...baseView,
90
+ startPosition: 1,
91
+ perPage: 10,
92
+ };
93
+ }
94
+
95
+ return {
96
+ ...baseView,
97
+ page: 1,
98
+ perPage: 10,
99
+ };
84
100
  } );
85
- const { data: shownData, paginationInfo: normalPaginationInfo } =
86
- useMemo( () => {
87
- return filterSortAndPaginate( data, view, fields );
88
- }, [ view ] );
101
+ const { data: shownData, paginationInfo } = useMemo( () => {
102
+ return filterSortAndPaginate( data, view, fields );
103
+ }, [ view ] );
89
104
 
90
105
  useEffect( () => {
91
- setView( ( prevView ) => ( {
92
- ...prevView,
93
- groupBy:
94
- isGrouped && ! infiniteScrollEnabled
95
- ? { field: 'type', direction: 'asc' }
96
- : undefined,
97
- infiniteScrollEnabled,
98
- } ) );
106
+ setView( ( prevView ) => {
107
+ const baseUpdates = {
108
+ groupBy:
109
+ isGrouped && ! infiniteScrollEnabled
110
+ ? { field: 'type', direction: 'asc' as const }
111
+ : undefined,
112
+ infiniteScrollEnabled,
113
+ };
114
+
115
+ if ( infiniteScrollEnabled ) {
116
+ return {
117
+ ...prevView,
118
+ ...baseUpdates,
119
+ startPosition: 1,
120
+ perPage: 15,
121
+ page: undefined,
122
+ } as View;
123
+ }
124
+
125
+ return {
126
+ ...prevView,
127
+ ...baseUpdates,
128
+ page: prevView.page ?? 1,
129
+ perPage: prevView.perPage ?? 10,
130
+ startPosition: undefined,
131
+ } as View;
132
+ } );
99
133
  }, [ isGrouped, infiniteScrollEnabled ] );
100
134
 
101
135
  const [ selection, setSelection ] = useState< string[] >(
@@ -129,24 +163,12 @@ const DataViewsPickerContent = ( {
129
163
  },
130
164
  ];
131
165
 
132
- const {
133
- data: infiniteScrollData,
134
- paginationInfo: infiniteScrollPaginationInfo,
135
- isLoadingMore,
136
- } = useInfiniteScroll( {
137
- view,
138
- setView,
139
- data: shownData,
140
- getItemId: ( item ) => item.id.toString(),
141
- totalDataLength: data.length,
142
- } );
143
-
144
166
  return (
145
167
  <>
146
168
  { infiniteScrollEnabled && (
147
169
  <style>{ `
148
170
  .dataviews-picker-wrapper {
149
- height: 600px;
171
+ height: 750px;
150
172
  overflow: auto;
151
173
  }
152
174
  ` }</style>
@@ -158,13 +180,8 @@ const DataViewsPickerContent = ( {
158
180
  setSelection( selectedIds );
159
181
  } }
160
182
  getItemId={ ( item ) => item.id.toString() }
161
- paginationInfo={
162
- infiniteScrollEnabled
163
- ? infiniteScrollPaginationInfo
164
- : normalPaginationInfo
165
- }
166
- data={ infiniteScrollEnabled ? infiniteScrollData : shownData }
167
- isLoading={ infiniteScrollEnabled ? isLoadingMore : undefined }
183
+ paginationInfo={ paginationInfo }
184
+ data={ shownData }
168
185
  view={ view }
169
186
  fields={ fields }
170
187
  onChangeView={ setView }
@@ -172,7 +189,7 @@ const DataViewsPickerContent = ( {
172
189
  itemListLabel="Galactic Bodies"
173
190
  defaultLayouts={ {
174
191
  [ LAYOUT_PICKER_GRID ]: {},
175
- [ LAYOUT_PICKER_TABLE ]: { perPage: 20 },
192
+ [ LAYOUT_PICKER_TABLE ]: {},
176
193
  } }
177
194
  />
178
195
  </>
@@ -296,87 +313,3 @@ export const WithModal = ( {
296
313
 
297
314
  WithModal.args = storyArgs;
298
315
  WithModal.argTypes = storyArgTypes;
299
-
300
- function useInfiniteScroll( {
301
- view,
302
- setView,
303
- data: shownData,
304
- getItemId,
305
- totalDataLength,
306
- }: {
307
- view: View;
308
- setView: ( view: View ) => void;
309
- data: SpaceObject[];
310
- getItemId: ( item: SpaceObject ) => string;
311
- totalDataLength: number;
312
- } ): {
313
- data: SpaceObject[];
314
- paginationInfo: {
315
- totalItems: number;
316
- totalPages: number;
317
- infiniteScrollHandler?: ( () => void ) | undefined;
318
- };
319
- isLoadingMore: boolean;
320
- hasMoreData: boolean;
321
- } {
322
- // Custom pagination handler that simulates server-side pagination
323
- const [ allLoadedRecords, setAllLoadedRecords ] = useState< SpaceObject[] >(
324
- []
325
- );
326
- const [ isLoadingMore, setIsLoadingMore ] = useState( false );
327
-
328
- const totalItems = totalDataLength;
329
- const totalPages = Math.ceil( totalItems / ( view.perPage || 10 ) );
330
- const currentPage = view.page || 1;
331
- const hasMoreData = currentPage < totalPages;
332
-
333
- const infiniteScrollHandler = useCallback( () => {
334
- if ( isLoadingMore || currentPage >= totalPages ) {
335
- return;
336
- }
337
-
338
- setIsLoadingMore( true );
339
-
340
- setView( {
341
- ...view,
342
- page: currentPage + 1,
343
- } );
344
- }, [ isLoadingMore, currentPage, totalPages, view, setView ] );
345
-
346
- // Initialize data on first load or when view changes significantly
347
- useEffect( () => {
348
- if ( currentPage === 1 || ! view.infiniteScrollEnabled ) {
349
- // First page - replace all data
350
- setAllLoadedRecords( shownData );
351
- } else {
352
- // Subsequent pages - append to existing data
353
- setAllLoadedRecords( ( prev ) => {
354
- const existingIds = new Set( prev.map( getItemId ) );
355
- const newRecords = shownData.filter(
356
- ( record ) => ! existingIds.has( getItemId( record ) )
357
- );
358
- return [ ...prev, ...newRecords ];
359
- } );
360
- }
361
- setIsLoadingMore( false );
362
- }, [
363
- view.search,
364
- view.filters,
365
- view.perPage,
366
- currentPage,
367
- view.infiniteScrollEnabled,
368
- ] );
369
-
370
- const paginationInfo = {
371
- totalItems,
372
- totalPages,
373
- infiniteScrollHandler,
374
- };
375
-
376
- return {
377
- data: allLoadedRecords,
378
- paginationInfo,
379
- isLoadingMore,
380
- hasMoreData,
381
- };
382
- }
@@ -110,6 +110,7 @@ type DataType = {
110
110
  booleanWithToggle: boolean;
111
111
  booleanWithElements: boolean;
112
112
  datetime: string;
113
+ datetimeCompact?: string;
113
114
  datetimeWithElements: string;
114
115
  date: string;
115
116
  dateWithElements: string;
@@ -150,6 +151,7 @@ const data: DataType[] = [
150
151
  booleanWithToggle: true,
151
152
  booleanWithElements: true,
152
153
  datetime: '2021-01-01T14:30:00Z',
154
+ datetimeCompact: '2021-01-01T14:30:00Z',
153
155
  datetimeWithElements: '1982-05-10T20:30:00Z',
154
156
  date: '2021-01-01',
155
157
  dateWithElements: '2021-01-01',
@@ -303,6 +305,16 @@ const fields: Field< DataType >[] = [
303
305
  label: 'Datetime',
304
306
  description: 'Help for datetime.',
305
307
  },
308
+ {
309
+ id: 'datetimeCompact',
310
+ type: 'datetime',
311
+ label: 'Datetime (compact)',
312
+ description: 'Datetime field without the calendar widget.',
313
+ Edit: {
314
+ control: 'datetime',
315
+ compact: true,
316
+ },
317
+ },
306
318
  {
307
319
  id: 'datetimeWithElements',
308
320
  type: 'datetime',
@@ -2,3 +2,6 @@
2
2
  * Internal dependencies
3
3
  */
4
4
  export { default as useFormValidity } from './use-form-validity';
5
+ export { default as useData } from './use-data';
6
+ export { useInfiniteScroll } from './use-infinite-scroll';
7
+ export { default as useSelectedItems } from './use-selected-items';