@wordpress/compose 8.4.0 → 8.6.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 (221) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/build/higher-order/compose.cjs.map +2 -2
  3. package/build/higher-order/if-condition/index.cjs.map +2 -2
  4. package/build/higher-order/pure/index.cjs.map +2 -2
  5. package/build/higher-order/with-global-events/index.cjs.map +2 -2
  6. package/build/higher-order/with-instance-id/index.cjs.map +2 -2
  7. package/build/higher-order/with-safe-timeout/index.cjs +1 -1
  8. package/build/higher-order/with-safe-timeout/index.cjs.map +2 -2
  9. package/build/higher-order/with-state/index.cjs.map +2 -2
  10. package/build/hooks/use-async-list/index.cjs.map +2 -2
  11. package/build/hooks/use-constrained-tabbing/index.cjs.map +2 -2
  12. package/build/hooks/use-copy-on-click/index.cjs.map +2 -2
  13. package/build/hooks/use-copy-to-clipboard/index.cjs.map +2 -2
  14. package/build/hooks/use-debounce/index.cjs.map +2 -2
  15. package/build/hooks/use-debounced-input/index.cjs.map +2 -2
  16. package/build/hooks/use-dialog/index.cjs.map +2 -2
  17. package/build/hooks/use-disabled/index.cjs.map +2 -2
  18. package/build/hooks/use-dragging/index.cjs.map +2 -2
  19. package/build/hooks/use-drop-zone/index.cjs.map +2 -2
  20. package/build/hooks/use-event/index.cjs.map +2 -2
  21. package/build/hooks/use-fixed-window-list/index.cjs +98 -92
  22. package/build/hooks/use-fixed-window-list/index.cjs.map +3 -3
  23. package/build/hooks/use-focus-outside/index.cjs.map +2 -2
  24. package/build/hooks/use-focus-return/index.cjs.map +2 -2
  25. package/build/hooks/use-focusable-iframe/index.cjs.map +2 -2
  26. package/build/hooks/use-instance-id/index.cjs.map +2 -2
  27. package/build/hooks/use-isomorphic-layout-effect/index.cjs.map +2 -2
  28. package/build/hooks/use-keyboard-shortcut/index.cjs.map +2 -2
  29. package/build/hooks/use-media-query/index.cjs.map +2 -2
  30. package/build/hooks/use-merge-refs/index.cjs.map +2 -2
  31. package/build/hooks/use-observable-value/index.cjs.map +2 -2
  32. package/build/hooks/use-previous/index.cjs.map +2 -2
  33. package/build/hooks/use-reduced-motion/index.cjs.map +2 -2
  34. package/build/hooks/use-ref-effect/index.cjs.map +2 -2
  35. package/build/hooks/use-resize-observer/index.cjs.map +2 -2
  36. package/build/hooks/use-resize-observer/legacy/index.cjs.map +2 -2
  37. package/build/hooks/use-resize-observer/use-resize-observer.cjs.map +2 -2
  38. package/build/hooks/use-state-with-history/index.cjs.map +2 -2
  39. package/build/hooks/use-throttle/index.cjs.map +2 -2
  40. package/build/hooks/use-viewport-match/index.cjs +1 -1
  41. package/build/hooks/use-viewport-match/index.cjs.map +2 -2
  42. package/build/hooks/use-warn-on-change/index.cjs.map +2 -2
  43. package/build/lock-unlock.cjs.map +2 -2
  44. package/build/private-apis.cjs.map +2 -2
  45. package/build/utils/create-higher-order-component/index.cjs.map +2 -2
  46. package/build/utils/throttle/index.cjs.map +2 -2
  47. package/build-module/higher-order/compose.mjs.map +2 -2
  48. package/build-module/higher-order/if-condition/index.mjs.map +2 -2
  49. package/build-module/higher-order/pure/index.mjs.map +2 -2
  50. package/build-module/higher-order/with-global-events/index.mjs.map +2 -2
  51. package/build-module/higher-order/with-instance-id/index.mjs.map +2 -2
  52. package/build-module/higher-order/with-safe-timeout/index.mjs +1 -1
  53. package/build-module/higher-order/with-safe-timeout/index.mjs.map +2 -2
  54. package/build-module/higher-order/with-state/index.mjs.map +2 -2
  55. package/build-module/hooks/use-async-list/index.mjs.map +2 -2
  56. package/build-module/hooks/use-constrained-tabbing/index.mjs.map +2 -2
  57. package/build-module/hooks/use-copy-on-click/index.mjs.map +2 -2
  58. package/build-module/hooks/use-copy-to-clipboard/index.mjs.map +2 -2
  59. package/build-module/hooks/use-debounce/index.mjs.map +2 -2
  60. package/build-module/hooks/use-debounced-input/index.mjs.map +2 -2
  61. package/build-module/hooks/use-dialog/index.mjs.map +2 -2
  62. package/build-module/hooks/use-disabled/index.mjs.map +2 -2
  63. package/build-module/hooks/use-dragging/index.mjs.map +2 -2
  64. package/build-module/hooks/use-drop-zone/index.mjs.map +2 -2
  65. package/build-module/hooks/use-event/index.mjs.map +2 -2
  66. package/build-module/hooks/use-fixed-window-list/index.mjs +89 -93
  67. package/build-module/hooks/use-fixed-window-list/index.mjs.map +2 -2
  68. package/build-module/hooks/use-focus-outside/index.mjs.map +2 -2
  69. package/build-module/hooks/use-focus-return/index.mjs.map +2 -2
  70. package/build-module/hooks/use-focusable-iframe/index.mjs.map +2 -2
  71. package/build-module/hooks/use-instance-id/index.mjs.map +2 -2
  72. package/build-module/hooks/use-isomorphic-layout-effect/index.mjs.map +2 -2
  73. package/build-module/hooks/use-keyboard-shortcut/index.mjs.map +2 -2
  74. package/build-module/hooks/use-media-query/index.mjs.map +2 -2
  75. package/build-module/hooks/use-merge-refs/index.mjs.map +2 -2
  76. package/build-module/hooks/use-observable-value/index.mjs.map +2 -2
  77. package/build-module/hooks/use-previous/index.mjs.map +2 -2
  78. package/build-module/hooks/use-reduced-motion/index.mjs.map +2 -2
  79. package/build-module/hooks/use-ref-effect/index.mjs.map +2 -2
  80. package/build-module/hooks/use-resize-observer/index.mjs.map +2 -2
  81. package/build-module/hooks/use-resize-observer/legacy/index.mjs.map +2 -2
  82. package/build-module/hooks/use-resize-observer/use-resize-observer.mjs.map +2 -2
  83. package/build-module/hooks/use-state-with-history/index.mjs.map +2 -2
  84. package/build-module/hooks/use-throttle/index.mjs.map +2 -2
  85. package/build-module/hooks/use-viewport-match/index.mjs +1 -1
  86. package/build-module/hooks/use-viewport-match/index.mjs.map +2 -2
  87. package/build-module/hooks/use-warn-on-change/index.mjs.map +2 -2
  88. package/build-module/lock-unlock.mjs.map +2 -2
  89. package/build-module/private-apis.mjs.map +2 -2
  90. package/build-module/utils/create-higher-order-component/index.mjs.map +2 -2
  91. package/build-module/utils/throttle/index.mjs.map +2 -2
  92. package/build-types/higher-order/compose.d.ts.map +1 -1
  93. package/build-types/higher-order/if-condition/index.d.ts +0 -3
  94. package/build-types/higher-order/if-condition/index.d.ts.map +1 -1
  95. package/build-types/higher-order/pure/index.d.ts +0 -3
  96. package/build-types/higher-order/pure/index.d.ts.map +1 -1
  97. package/build-types/higher-order/with-global-events/index.d.ts.map +1 -1
  98. package/build-types/higher-order/with-instance-id/index.d.ts +0 -3
  99. package/build-types/higher-order/with-instance-id/index.d.ts.map +1 -1
  100. package/build-types/higher-order/with-safe-timeout/index.d.ts +0 -3
  101. package/build-types/higher-order/with-safe-timeout/index.d.ts.map +1 -1
  102. package/build-types/higher-order/with-state/index.d.ts.map +1 -1
  103. package/build-types/hooks/use-async-list/index.d.ts.map +1 -1
  104. package/build-types/hooks/use-constrained-tabbing/index.d.ts.map +1 -1
  105. package/build-types/hooks/use-copy-on-click/index.d.ts.map +1 -1
  106. package/build-types/hooks/use-copy-to-clipboard/index.d.ts.map +1 -1
  107. package/build-types/hooks/use-debounce/index.d.ts.map +1 -1
  108. package/build-types/hooks/use-debounced-input/index.d.ts.map +1 -1
  109. package/build-types/hooks/use-dialog/index.d.ts +0 -3
  110. package/build-types/hooks/use-dialog/index.d.ts.map +1 -1
  111. package/build-types/hooks/use-disabled/index.d.ts.map +1 -1
  112. package/build-types/hooks/use-dragging/index.d.ts.map +1 -1
  113. package/build-types/hooks/use-drop-zone/index.d.ts.map +1 -1
  114. package/build-types/hooks/use-event/index.d.ts.map +1 -1
  115. package/build-types/hooks/use-fixed-window-list/index.d.ts +1 -1
  116. package/build-types/hooks/use-fixed-window-list/index.d.ts.map +1 -1
  117. package/build-types/hooks/use-focus-outside/index.d.ts.map +1 -1
  118. package/build-types/hooks/use-focus-return/index.d.ts.map +1 -1
  119. package/build-types/hooks/use-focusable-iframe/index.d.ts +0 -3
  120. package/build-types/hooks/use-focusable-iframe/index.d.ts.map +1 -1
  121. package/build-types/hooks/use-instance-id/index.d.ts.map +1 -1
  122. package/build-types/hooks/use-isomorphic-layout-effect/index.d.ts +0 -3
  123. package/build-types/hooks/use-isomorphic-layout-effect/index.d.ts.map +1 -1
  124. package/build-types/hooks/use-keyboard-shortcut/index.d.ts +0 -3
  125. package/build-types/hooks/use-keyboard-shortcut/index.d.ts.map +1 -1
  126. package/build-types/hooks/use-media-query/index.d.ts.map +1 -1
  127. package/build-types/hooks/use-merge-refs/index.d.ts.map +1 -1
  128. package/build-types/hooks/use-observable-value/index.d.ts +0 -3
  129. package/build-types/hooks/use-observable-value/index.d.ts.map +1 -1
  130. package/build-types/hooks/use-previous/index.d.ts.map +1 -1
  131. package/build-types/hooks/use-reduced-motion/index.d.ts.map +1 -1
  132. package/build-types/hooks/use-ref-effect/index.d.ts +0 -3
  133. package/build-types/hooks/use-ref-effect/index.d.ts.map +1 -1
  134. package/build-types/hooks/use-resize-observer/index.d.ts +1 -4
  135. package/build-types/hooks/use-resize-observer/index.d.ts.map +1 -1
  136. package/build-types/hooks/use-resize-observer/legacy/index.d.ts +0 -3
  137. package/build-types/hooks/use-resize-observer/legacy/index.d.ts.map +1 -1
  138. package/build-types/hooks/use-resize-observer/use-resize-observer.d.ts.map +1 -1
  139. package/build-types/hooks/use-state-with-history/index.d.ts.map +1 -1
  140. package/build-types/hooks/use-throttle/index.d.ts.map +1 -1
  141. package/build-types/hooks/use-viewport-match/index.d.ts.map +1 -1
  142. package/build-types/hooks/use-warn-on-change/index.d.ts.map +1 -1
  143. package/build-types/lock-unlock.d.ts.map +1 -1
  144. package/build-types/private-apis.d.ts.map +1 -1
  145. package/build-types/utils/create-higher-order-component/index.d.ts.map +1 -1
  146. package/build-types/utils/throttle/index.d.ts +0 -39
  147. package/build-types/utils/throttle/index.d.ts.map +1 -1
  148. package/package.json +10 -10
  149. package/src/higher-order/compose.ts +0 -3
  150. package/src/higher-order/if-condition/index.tsx +0 -7
  151. package/src/higher-order/pure/index.tsx +0 -11
  152. package/src/higher-order/pure/test/index.js +0 -11
  153. package/src/higher-order/test/compose.ts +0 -3
  154. package/src/higher-order/test/pipe.ts +0 -3
  155. package/src/higher-order/with-global-events/index.js +0 -8
  156. package/src/higher-order/with-global-events/test/index.js +0 -11
  157. package/src/higher-order/with-global-events/test/listener.js +0 -3
  158. package/src/higher-order/with-instance-id/README.md +0 -3
  159. package/src/higher-order/with-instance-id/index.tsx +1 -4
  160. package/src/higher-order/with-instance-id/test/index.js +0 -7
  161. package/src/higher-order/with-safe-timeout/README.md +0 -3
  162. package/src/higher-order/with-safe-timeout/index.tsx +1 -8
  163. package/src/higher-order/with-state/README.md +0 -3
  164. package/src/higher-order/with-state/index.js +0 -7
  165. package/src/higher-order/with-state/test/index.js +0 -7
  166. package/src/hooks/use-async-list/index.ts +0 -3
  167. package/src/hooks/use-constrained-tabbing/index.ts +0 -7
  168. package/src/hooks/use-copy-on-click/index.ts +0 -7
  169. package/src/hooks/use-copy-on-click/test/index.tsx +0 -11
  170. package/src/hooks/use-copy-to-clipboard/index.ts +0 -7
  171. package/src/hooks/use-copy-to-clipboard/test/index.tsx +0 -7
  172. package/src/hooks/use-debounce/index.ts +0 -11
  173. package/src/hooks/use-debounced-input/index.ts +0 -7
  174. package/src/hooks/use-dialog/index.ts +0 -11
  175. package/src/hooks/use-dialog/test/index.tsx +0 -7
  176. package/src/hooks/use-disabled/index.ts +0 -3
  177. package/src/hooks/use-disabled/test/index.js +0 -11
  178. package/src/hooks/use-dragging/README.md +0 -3
  179. package/src/hooks/use-dragging/index.ts +0 -7
  180. package/src/hooks/use-drop-zone/index.ts +0 -3
  181. package/src/hooks/use-drop-zone/test/index.js +0 -11
  182. package/src/hooks/use-event/index.ts +0 -3
  183. package/src/hooks/use-fixed-window-list/index.ts +128 -116
  184. package/src/hooks/use-focus-outside/index.ts +0 -3
  185. package/src/hooks/use-focus-outside/test/index.js +0 -7
  186. package/src/hooks/use-focus-return/index.ts +0 -3
  187. package/src/hooks/use-focusable-iframe/index.ts +0 -7
  188. package/src/hooks/use-instance-id/README.md +0 -3
  189. package/src/hooks/use-instance-id/index.ts +0 -3
  190. package/src/hooks/use-instance-id/test/index.js +0 -7
  191. package/src/hooks/use-isomorphic-layout-effect/index.ts +0 -3
  192. package/src/hooks/use-keyboard-shortcut/index.ts +0 -7
  193. package/src/hooks/use-media-query/index.ts +0 -3
  194. package/src/hooks/use-media-query/test/index.js +0 -7
  195. package/src/hooks/use-media-query/test/ssr.js +0 -8
  196. package/src/hooks/use-merge-refs/index.ts +0 -3
  197. package/src/hooks/use-merge-refs/test/index.js +0 -11
  198. package/src/hooks/use-observable-value/index.ts +0 -7
  199. package/src/hooks/use-observable-value/test/index.js +0 -7
  200. package/src/hooks/use-previous/README.md +0 -3
  201. package/src/hooks/use-previous/index.ts +0 -3
  202. package/src/hooks/use-reduced-motion/index.ts +0 -3
  203. package/src/hooks/use-ref-effect/index.ts +0 -7
  204. package/src/hooks/use-resize-observer/index.ts +1 -7
  205. package/src/hooks/use-resize-observer/legacy/index.tsx +0 -10
  206. package/src/hooks/use-resize-observer/use-resize-observer.ts +0 -6
  207. package/src/hooks/use-state-with-history/index.ts +0 -3
  208. package/src/hooks/use-state-with-history/test/index.js +0 -7
  209. package/src/hooks/use-throttle/index.ts +0 -11
  210. package/src/hooks/use-viewport-match/index.ts +3 -8
  211. package/src/hooks/use-viewport-match/test/index.js +6 -15
  212. package/src/hooks/use-warn-on-change/index.ts +0 -3
  213. package/src/lock-unlock.ts +0 -3
  214. package/src/private-apis.ts +0 -3
  215. package/src/utils/create-higher-order-component/index.ts +0 -3
  216. package/src/utils/create-higher-order-component/test/index.js +0 -7
  217. package/src/utils/debounce/test/index.ts +0 -3
  218. package/src/utils/observable-map/test/index.js +0 -3
  219. package/src/utils/subscribe-delegated-listener/test/index.js +0 -3
  220. package/src/utils/throttle/index.ts +0 -4
  221. package/src/utils/throttle/test/index.ts +0 -3
@@ -1,21 +1,10 @@
1
- /**
2
- * External dependencies
3
- */
4
1
  import type {
5
2
  KeyboardEvent,
6
3
  KeyboardEventHandler,
7
4
  RefCallback,
8
5
  SyntheticEvent,
9
6
  } from 'react';
10
-
11
- /**
12
- * WordPress dependencies
13
- */
14
7
  import { useRef, useEffect, useCallback } from '@wordpress/element';
15
-
16
- /**
17
- * Internal dependencies
18
- */
19
8
  import useConstrainedTabbing from '../use-constrained-tabbing';
20
9
  import { useFocusOnMount } from '../use-focus-on-mount';
21
10
  import useFocusReturn from '../use-focus-return';
@@ -1,13 +1,6 @@
1
- /**
2
- * External dependencies
3
- */
4
1
  import { render, screen } from '@testing-library/react';
5
2
  import userEvent from '@testing-library/user-event';
6
3
  import { createPortal } from 'react-dom';
7
-
8
- /**
9
- * Internal dependencies
10
- */
11
4
  import useDialog from '..';
12
5
 
13
6
  function Dialog( { onClose }: { onClose?: () => void } ) {
@@ -1,6 +1,3 @@
1
- /**
2
- * Internal dependencies
3
- */
4
1
  import { debounce } from '../../utils/debounce';
5
2
  import useRefEffect from '../use-ref-effect';
6
3
 
@@ -1,16 +1,5 @@
1
- /**
2
- * External dependencies
3
- */
4
1
  import { render, screen, waitFor } from '@testing-library/react';
5
-
6
- /**
7
- * WordPress dependencies
8
- */
9
2
  import { forwardRef } from '@wordpress/element';
10
-
11
- /**
12
- * Internal dependencies
13
- */
14
3
  import useDisabled from '../';
15
4
 
16
5
  describe( 'useDisabled', () => {
@@ -54,9 +54,6 @@ A boolean value, when true it means dragging is currently taking place; when fal
54
54
  The following example allows us to drag & drop a red square around the entire viewport.
55
55
 
56
56
  ```jsx
57
- /**
58
- * WordPress dependencies
59
- */
60
57
  import { useState, useCallback } from 'react';
61
58
  import { __experimentalUseDragging as useDragging } from '@wordpress/compose';
62
59
 
@@ -1,11 +1,4 @@
1
- /**
2
- * WordPress dependencies
3
- */
4
1
  import { useCallback, useEffect, useRef, useState } from '@wordpress/element';
5
-
6
- /**
7
- * Internal dependencies
8
- */
9
2
  import useIsomorphicLayoutEffect from '../use-isomorphic-layout-effect';
10
3
  import type { DraggingProps, DraggingReturn } from './types';
11
4
 
@@ -1,6 +1,3 @@
1
- /**
2
- * Internal dependencies
3
- */
4
1
  import useRefEffect from '../use-ref-effect';
5
2
  import useEvent from '../use-event';
6
3
  import type { UseDropZoneProps } from './types';
@@ -1,16 +1,5 @@
1
- /**
2
- * External dependencies
3
- */
4
1
  import { render, screen } from '@testing-library/react';
5
-
6
- /**
7
- * WordPress dependencies
8
- */
9
2
  import { useState } from '@wordpress/element';
10
-
11
- /**
12
- * Internal dependencies
13
- */
14
3
  import useDropZone from '../';
15
4
 
16
5
  describe( 'useDropZone', () => {
@@ -1,6 +1,3 @@
1
- /**
2
- * WordPress dependencies
3
- */
4
1
  import { useRef, useInsertionEffect, useCallback } from '@wordpress/element';
5
2
 
6
3
  /**
@@ -1,19 +1,12 @@
1
- /**
2
- * WordPress dependencies
3
- */
4
- import { useState, useLayoutEffect } from '@wordpress/element';
1
+ import { useState, useLayoutEffect, useRef } from '@wordpress/element';
5
2
  import { getScrollContainer } from '@wordpress/dom';
6
3
  import { PAGEUP, PAGEDOWN, HOME, END } from '@wordpress/keycodes';
7
-
8
- /**
9
- * Internal dependencies
10
- */
11
- import { debounce } from '../../utils/debounce';
4
+ import useEvent from '../use-event';
12
5
 
13
6
  const DEFAULT_INIT_WINDOW_SIZE = 30;
14
7
 
15
8
  interface FixedWindowList {
16
- /** Items visible in the current viewport */
9
+ /** Items visible in the viewport, as of the last rendered window */
17
10
  visibleItems: number;
18
11
  /** Start index of the window */
19
12
  start: number;
@@ -51,8 +44,12 @@ export default function useFixedWindowList(
51
44
  FixedWindowList,
52
45
  React.Dispatch< React.SetStateAction< FixedWindowList > >,
53
46
  ] {
54
- const initWindowSize = options?.initWindowSize ?? DEFAULT_INIT_WINDOW_SIZE;
55
- const useWindowing = options?.useWindowing ?? true;
47
+ const {
48
+ windowOverscan,
49
+ useWindowing = true,
50
+ initWindowSize = DEFAULT_INIT_WINDOW_SIZE,
51
+ expandedState,
52
+ } = options ?? {};
56
53
 
57
54
  const [ fixedListWindow, setFixedListWindow ] = useState< FixedWindowList >(
58
55
  {
@@ -65,137 +62,152 @@ export default function useFixedWindowList(
65
62
  }
66
63
  );
67
64
 
68
- useLayoutEffect( () => {
69
- if ( ! useWindowing ) {
65
+ // Kept out of state so that measuring the list does not, on its own, force a
66
+ // re-render. Only the rendered window does that.
67
+ const visibleItemsRef = useRef( initWindowSize );
68
+
69
+ // The measuring effect re-runs whenever the list changes, so the effect
70
+ // running can't on its own tell the very first measurement from later ones.
71
+ const isFirstMeasurementRef = useRef( true );
72
+
73
+ // Stable identity, so the listeners below never have to be re-attached, and
74
+ // reads the latest props on every call.
75
+ const measureWindow = useEvent( ( initRender?: boolean ) => {
76
+ const scrollContainer = getScrollContainer( elementRef.current );
77
+ if ( ! scrollContainer ) {
70
78
  return;
71
79
  }
72
- const scrollContainer = getScrollContainer( elementRef.current );
73
- /**
74
- * Measures and sets the window of items to render based on the scroll position
75
- *
76
- * @param {boolean} [initRender] Indicates if this is the initial render
77
- * @return {void}
78
- */
79
- const measureWindow = ( initRender?: boolean ) => {
80
- if ( ! scrollContainer ) {
81
- return;
82
- }
83
- const visibleItems = Math.ceil(
84
- scrollContainer.clientHeight / itemHeight
85
- );
86
- // Aim to keep opening list view fast, afterward we can optimize for scrolling.
87
- const windowOverscan = initRender
88
- ? visibleItems
89
- : options?.windowOverscan ?? visibleItems;
90
- const firstViewableIndex = Math.floor(
91
- scrollContainer.scrollTop / itemHeight
92
- );
93
- const start = Math.max( 0, firstViewableIndex - windowOverscan );
94
- const end = Math.min(
95
- totalItems - 1,
96
- firstViewableIndex + visibleItems + windowOverscan
97
- );
98
- setFixedListWindow( ( lastWindow ) => {
99
- const nextWindow = {
100
- visibleItems,
101
- start,
102
- end,
103
- itemInView: ( index: number ) => {
104
- return start <= index && index <= end;
105
- },
106
- };
107
- if (
108
- lastWindow.start !== nextWindow.start ||
109
- lastWindow.end !== nextWindow.end ||
110
- lastWindow.visibleItems !== nextWindow.visibleItems
111
- ) {
112
- return nextWindow;
113
- }
114
- return lastWindow;
115
- } );
116
- };
117
-
118
- measureWindow( true );
119
- const debounceMeasureList = debounce( () => {
120
- measureWindow();
121
- }, 16 );
122
- scrollContainer?.addEventListener( 'scroll', debounceMeasureList );
123
- scrollContainer?.ownerDocument?.defaultView?.addEventListener(
124
- 'resize',
125
- debounceMeasureList
80
+ const visibleItems = Math.ceil(
81
+ scrollContainer.clientHeight / itemHeight
126
82
  );
127
- scrollContainer?.ownerDocument?.defaultView?.addEventListener(
128
- 'resize',
129
- debounceMeasureList
83
+ visibleItemsRef.current = visibleItems;
84
+ const isFirstMeasurement = isFirstMeasurementRef.current;
85
+ isFirstMeasurementRef.current = false;
86
+ // Aim to keep opening list view fast, afterward we can optimize for scrolling.
87
+ const overscan = initRender
88
+ ? visibleItems
89
+ : windowOverscan ?? visibleItems;
90
+ const firstViewableIndex = Math.floor(
91
+ scrollContainer.scrollTop / itemHeight
130
92
  );
93
+ const start = Math.max( 0, firstViewableIndex - overscan );
94
+ const end = Math.min(
95
+ totalItems - 1,
96
+ firstViewableIndex + visibleItems + overscan
97
+ );
98
+ setFixedListWindow( ( lastWindow ) => {
99
+ // Rendering the window is the expensive part, and for the items in
100
+ // `lastWindow` it is already paid for. When the next window has
101
+ // nothing to add, keep the current one: a window that only shrinks
102
+ // drops nodes that are known to be needed again and forces another
103
+ // style recalculation, with nothing new to show for it.
104
+ if ( lastWindow.start <= start && lastWindow.end >= end ) {
105
+ return lastWindow;
106
+ }
107
+ // The first window is rendered before the list can be measured, so
108
+ // it is sized by `initWindowSize` rather than by the viewport, and
109
+ // the measured window is normally wider than it by the overscan.
110
+ // Nothing has painted yet though, so there is no scrolling for the
111
+ // overscan to absorb: covering the visible items is enough, and
112
+ // keeping that window saves a render pass while the list opens.
113
+ if (
114
+ isFirstMeasurement &&
115
+ lastWindow.start <= firstViewableIndex &&
116
+ lastWindow.end >= firstViewableIndex + visibleItems
117
+ ) {
118
+ return lastWindow;
119
+ }
120
+ return {
121
+ visibleItems,
122
+ start,
123
+ end,
124
+ itemInView: ( index: number ) => {
125
+ return start <= index && index <= end;
126
+ },
127
+ };
128
+ } );
129
+ } );
131
130
 
132
- return () => {
133
- scrollContainer?.removeEventListener(
134
- 'scroll',
135
- debounceMeasureList
136
- );
137
- scrollContainer?.ownerDocument?.defaultView?.removeEventListener(
138
- 'resize',
139
- debounceMeasureList
140
- );
141
- };
142
- }, [
143
- itemHeight,
144
- elementRef,
145
- totalItems,
146
- options?.expandedState,
147
- options?.windowOverscan,
148
- useWindowing,
149
- ] );
150
-
151
- useLayoutEffect( () => {
152
- if ( ! useWindowing ) {
153
- return;
154
- }
155
- const scrollContainer = getScrollContainer( elementRef.current );
156
- const handleKeyDown = ( event: KeyboardEvent ) => {
131
+ const handleKeyDown = useEvent(
132
+ ( event: KeyboardEvent, scrollContainer: Element ) => {
157
133
  switch ( event.keyCode ) {
158
134
  case HOME: {
159
- return scrollContainer?.scrollTo( { top: 0 } );
135
+ return scrollContainer.scrollTo( { top: 0 } );
160
136
  }
161
137
  case END: {
162
- return scrollContainer?.scrollTo( {
138
+ return scrollContainer.scrollTo( {
163
139
  top: totalItems * itemHeight,
164
140
  } );
165
141
  }
166
142
  case PAGEUP: {
167
- return scrollContainer?.scrollTo( {
143
+ return scrollContainer.scrollTo( {
168
144
  top:
169
145
  scrollContainer.scrollTop -
170
- fixedListWindow.visibleItems * itemHeight,
146
+ visibleItemsRef.current * itemHeight,
171
147
  } );
172
148
  }
173
149
  case PAGEDOWN: {
174
- return scrollContainer?.scrollTo( {
150
+ return scrollContainer.scrollTo( {
175
151
  top:
176
152
  scrollContainer.scrollTop +
177
- fixedListWindow.visibleItems * itemHeight,
153
+ visibleItemsRef.current * itemHeight,
178
154
  } );
179
155
  }
180
156
  }
181
- };
182
- scrollContainer?.ownerDocument?.defaultView?.addEventListener(
183
- 'keydown',
184
- handleKeyDown
185
- );
157
+ }
158
+ );
159
+
160
+ // Measure whenever something that the window is derived from changes.
161
+ useLayoutEffect( () => {
162
+ if ( ! useWindowing ) {
163
+ return;
164
+ }
165
+ measureWindow( true );
166
+ }, [
167
+ useWindowing,
168
+ measureWindow,
169
+ itemHeight,
170
+ totalItems,
171
+ windowOverscan,
172
+ expandedState,
173
+ ] );
174
+
175
+ // Only ever attaches and detaches listeners. The deps are the things that
176
+ // can change which element the scroll container is, or whether there is one
177
+ // at all: a list that is too short to overflow has no scroll container to
178
+ // attach to, and it grows into one by gaining items or by being expanded.
179
+ useLayoutEffect( () => {
180
+ if ( ! useWindowing ) {
181
+ return;
182
+ }
183
+ const scrollContainer = getScrollContainer( elementRef.current );
184
+ if ( ! scrollContainer ) {
185
+ return;
186
+ }
187
+ const { defaultView } = scrollContainer.ownerDocument;
188
+ // `scroll` and `resize` already fire at about the rendering rate, so
189
+ // there is nothing to gain from debouncing them.
190
+ const onMeasure = () => measureWindow();
191
+ const onKeyDown = ( event: KeyboardEvent ) =>
192
+ handleKeyDown( event, scrollContainer );
193
+
194
+ scrollContainer.addEventListener( 'scroll', onMeasure );
195
+ defaultView?.addEventListener( 'resize', onMeasure );
196
+ defaultView?.addEventListener( 'keydown', onKeyDown );
197
+
186
198
  return () => {
187
- scrollContainer?.ownerDocument?.defaultView?.removeEventListener(
188
- 'keydown',
189
- handleKeyDown
190
- );
199
+ scrollContainer.removeEventListener( 'scroll', onMeasure );
200
+ defaultView?.removeEventListener( 'resize', onMeasure );
201
+ defaultView?.removeEventListener( 'keydown', onKeyDown );
191
202
  };
192
203
  }, [
193
- totalItems,
194
- itemHeight,
195
- elementRef,
196
- fixedListWindow.visibleItems,
197
204
  useWindowing,
198
- options?.expandedState,
205
+ elementRef,
206
+ itemHeight,
207
+ totalItems,
208
+ expandedState,
209
+ measureWindow,
210
+ handleKeyDown,
199
211
  ] );
200
212
 
201
213
  return [ fixedListWindow, setFixedListWindow ];
@@ -1,6 +1,3 @@
1
- /**
2
- * WordPress dependencies
3
- */
4
1
  import { useCallback, useEffect, useRef } from '@wordpress/element';
5
2
 
6
3
  /**
@@ -1,12 +1,5 @@
1
- /**
2
- * External dependencies
3
- */
4
1
  import { render, screen } from '@testing-library/react';
5
2
  import userEvent from '@testing-library/user-event';
6
-
7
- /**
8
- * Internal dependencies
9
- */
10
3
  import useFocusOutside from '../';
11
4
 
12
5
  const FocusOutsideComponent = ( { onFocusOutside: callback } ) => (
@@ -1,6 +1,3 @@
1
- /**
2
- * WordPress dependencies
3
- */
4
1
  import { useRef, useEffect, useCallback } from '@wordpress/element';
5
2
 
6
3
  let origin: Element | null = null;
@@ -1,11 +1,4 @@
1
- /**
2
- * External dependencies
3
- */
4
1
  import type { RefCallback } from 'react';
5
-
6
- /**
7
- * Internal dependencies
8
- */
9
2
  import useRefEffect from '../use-ref-effect';
10
3
 
11
4
  /**
@@ -5,9 +5,6 @@ Some components need to generate a unique id for each instance. This could serve
5
5
  ## Usage
6
6
 
7
7
  ```jsx
8
- /**
9
- * WordPress dependencies
10
- */
11
8
  import { useInstanceId } from '@wordpress/compose';
12
9
 
13
10
  function MyCustomElement() {
@@ -1,6 +1,3 @@
1
- /**
2
- * WordPress dependencies
3
- */
4
1
  import { useMemo } from '@wordpress/element';
5
2
 
6
3
  const instanceMap = new WeakMap< object, number >();
@@ -1,11 +1,4 @@
1
- /**
2
- * External dependencies
3
- */
4
1
  import { render } from '@testing-library/react';
5
-
6
- /**
7
- * Internal dependencies
8
- */
9
2
  import useInstanceId from '../';
10
3
 
11
4
  describe( 'useInstanceId', () => {
@@ -1,6 +1,3 @@
1
- /**
2
- * WordPress dependencies
3
- */
4
1
  import { useEffect, useLayoutEffect } from '@wordpress/element';
5
2
 
6
3
  /**
@@ -1,13 +1,6 @@
1
- /**
2
- * External dependencies
3
- */
4
1
  import Mousetrap from 'mousetrap';
5
2
  import 'mousetrap/plugins/global-bind/mousetrap-global-bind.js';
6
3
  import type { ExtendedKeyboardEvent } from 'mousetrap';
7
-
8
- /**
9
- * WordPress dependencies
10
- */
11
4
  import type { RefObject } from '@wordpress/element';
12
5
  import { useEffect, useRef } from '@wordpress/element';
13
6
  import { isAppleOS } from '@wordpress/keycodes';
@@ -1,6 +1,3 @@
1
- /**
2
- * WordPress dependencies
3
- */
4
1
  import { useSyncExternalStore } from '@wordpress/element';
5
2
 
6
3
  type MQLSubscriber = {
@@ -1,12 +1,5 @@
1
- /**
2
- * External dependencies
3
- */
4
1
  import { act, render } from '@testing-library/react';
5
2
  import { matchMedia, setMedia } from 'mock-match-media';
6
-
7
- /**
8
- * Internal dependencies
9
- */
10
3
  import useMediaQuery from '../';
11
4
 
12
5
  const TestComponent = ( { query } ) => {
@@ -1,15 +1,7 @@
1
1
  /**
2
2
  * @jest-environment node
3
3
  */
4
-
5
- /**
6
- * External dependencies
7
- */
8
4
  import { renderToString } from 'react-dom/server';
9
-
10
- /**
11
- * Internal dependencies
12
- */
13
5
  import useMediaQuery from '../';
14
6
  import useViewportMatch from '../../use-viewport-match';
15
7
 
@@ -1,6 +1,3 @@
1
- /**
2
- * WordPress dependencies
3
- */
4
1
  import { useRef, useCallback, useLayoutEffect } from '@wordpress/element';
5
2
  import type { MutableRefObject, Ref, RefCallback } from 'react';
6
3
 
@@ -1,16 +1,5 @@
1
- /**
2
- * External dependencies
3
- */
4
1
  import { render, screen, fireEvent } from '@testing-library/react';
5
-
6
- /**
7
- * WordPress dependencies
8
- */
9
2
  import { useCallback, useState } from '@wordpress/element';
10
-
11
- /**
12
- * Internal dependencies
13
- */
14
3
  import useMergeRefs from '../';
15
4
 
16
5
  describe( 'useMergeRefs', () => {
@@ -1,11 +1,4 @@
1
- /**
2
- * WordPress dependencies
3
- */
4
1
  import { useMemo, useSyncExternalStore } from '@wordpress/element';
5
-
6
- /**
7
- * Internal dependencies
8
- */
9
2
  import type { ObservableMap } from '../../utils/observable-map';
10
3
 
11
4
  /**
@@ -1,11 +1,4 @@
1
- /**
2
- * External dependencies
3
- */
4
1
  import { render, screen, act } from '@testing-library/react';
5
-
6
- /**
7
- * Internal dependencies
8
- */
9
2
  import { observableMap } from '../../../utils/observable-map';
10
3
  import useObservableValue from '..';
11
4
 
@@ -5,9 +5,6 @@ Sometimes you need to get the value something had on the previous render. `usePr
5
5
  ## Usage
6
6
 
7
7
  ```jsx
8
- /**
9
- * WordPress dependencies
10
- */
11
8
  import { useEffect, useState } from 'react';
12
9
  import { usePrevious } from '@wordpress/compose';
13
10
 
@@ -1,6 +1,3 @@
1
- /**
2
- * WordPress dependencies
3
- */
4
1
  import { useEffect, useRef } from '@wordpress/element';
5
2
 
6
3
  /**
@@ -1,6 +1,3 @@
1
- /**
2
- * Internal dependencies
3
- */
4
1
  import useMediaQuery from '../use-media-query';
5
2
 
6
3
  /**
@@ -1,11 +1,4 @@
1
- /**
2
- * External dependencies
3
- */
4
1
  import type { DependencyList, RefCallback } from 'react';
5
-
6
- /**
7
- * WordPress dependencies
8
- */
9
2
  import { useCallback, useRef } from '@wordpress/element';
10
3
 
11
4
  /**
@@ -1,13 +1,7 @@
1
- /**
2
- * Internal dependencies
3
- */
1
+ import type { ReactElement } from 'react';
4
2
  import { useResizeObserver as _useResizeObserver } from './use-resize-observer';
5
3
  import type { ObservedSize } from './legacy';
6
4
  import _useLegacyResizeObserver from './legacy';
7
- /**
8
- * External dependencies
9
- */
10
- import type { ReactElement } from 'react';
11
5
 
12
6
  /**
13
7
  * Sets up a [`ResizeObserver`](https://developer.mozilla.org/en-US/docs/Web/API/Resize_Observer_API)
@@ -1,15 +1,5 @@
1
- /**
2
- * External dependencies
3
- */
4
1
  import type { ReactElement } from 'react';
5
-
6
- /**
7
- * WordPress dependencies
8
- */
9
2
  import { useCallback, useRef, useState } from '@wordpress/element';
10
- /**
11
- * Internal dependencies
12
- */
13
3
  import { useResizeObserver } from '../use-resize-observer';
14
4
 
15
5
  export type ObservedSize = {