@wordpress/compose 5.0.1 → 5.0.5

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 (89) hide show
  1. package/README.md +12 -3
  2. package/build/higher-order/if-condition/index.js.map +1 -1
  3. package/build/higher-order/pure/index.js.map +1 -1
  4. package/build/higher-order/with-instance-id/index.js.map +1 -1
  5. package/build/higher-order/with-safe-timeout/index.js.map +1 -1
  6. package/build/hooks/use-constrained-tabbing/index.js +46 -43
  7. package/build/hooks/use-constrained-tabbing/index.js.map +1 -1
  8. package/build/hooks/use-debounce/index.js +1 -1
  9. package/build/hooks/use-debounce/index.js.map +1 -1
  10. package/build/hooks/use-drop-zone/index.js +12 -6
  11. package/build/hooks/use-drop-zone/index.js.map +1 -1
  12. package/build/hooks/use-fixed-window-list/index.js +175 -0
  13. package/build/hooks/use-fixed-window-list/index.js.map +1 -0
  14. package/build/hooks/use-focusable-iframe/index.js +50 -0
  15. package/build/hooks/use-focusable-iframe/index.js.map +1 -0
  16. package/build/hooks/use-previous/index.js +3 -14
  17. package/build/hooks/use-previous/index.js.map +1 -1
  18. package/build/hooks/use-reduced-motion/index.js +1 -7
  19. package/build/hooks/use-reduced-motion/index.js.map +1 -1
  20. package/build/hooks/use-throttle/index.js +1 -1
  21. package/build/hooks/use-throttle/index.js.map +1 -1
  22. package/build/index.js +16 -0
  23. package/build/index.js.map +1 -1
  24. package/build-module/higher-order/if-condition/index.js +1 -1
  25. package/build-module/higher-order/if-condition/index.js.map +1 -1
  26. package/build-module/higher-order/pure/index.js +1 -1
  27. package/build-module/higher-order/pure/index.js.map +1 -1
  28. package/build-module/higher-order/with-instance-id/index.js +1 -2
  29. package/build-module/higher-order/with-instance-id/index.js.map +1 -1
  30. package/build-module/higher-order/with-safe-timeout/index.js +1 -1
  31. package/build-module/higher-order/with-safe-timeout/index.js.map +1 -1
  32. package/build-module/hooks/use-constrained-tabbing/index.js +41 -40
  33. package/build-module/hooks/use-constrained-tabbing/index.js.map +1 -1
  34. package/build-module/hooks/use-debounce/index.js +1 -1
  35. package/build-module/hooks/use-debounce/index.js.map +1 -1
  36. package/build-module/hooks/use-drop-zone/index.js +12 -6
  37. package/build-module/hooks/use-drop-zone/index.js.map +1 -1
  38. package/build-module/hooks/use-fixed-window-list/index.js +164 -0
  39. package/build-module/hooks/use-fixed-window-list/index.js.map +1 -0
  40. package/build-module/hooks/use-focusable-iframe/index.js +40 -0
  41. package/build-module/hooks/use-focusable-iframe/index.js.map +1 -0
  42. package/build-module/hooks/use-previous/index.js +3 -14
  43. package/build-module/hooks/use-previous/index.js.map +1 -1
  44. package/build-module/hooks/use-reduced-motion/index.js +2 -8
  45. package/build-module/hooks/use-reduced-motion/index.js.map +1 -1
  46. package/build-module/hooks/use-throttle/index.js +1 -1
  47. package/build-module/hooks/use-throttle/index.js.map +1 -1
  48. package/build-module/index.js +2 -0
  49. package/build-module/index.js.map +1 -1
  50. package/build-types/higher-order/if-condition/index.d.ts.map +1 -1
  51. package/build-types/higher-order/pure/index.d.ts.map +1 -1
  52. package/build-types/higher-order/with-instance-id/index.d.ts.map +1 -1
  53. package/build-types/higher-order/with-safe-timeout/index.d.ts.map +1 -1
  54. package/build-types/hooks/use-constrained-tabbing/index.d.ts.map +1 -1
  55. package/build-types/hooks/use-debounce/index.d.ts +2 -2
  56. package/build-types/hooks/use-debounce/index.d.ts.map +1 -1
  57. package/build-types/hooks/use-drop-zone/index.d.ts.map +1 -1
  58. package/build-types/hooks/use-fixed-window-list/index.d.ts +57 -0
  59. package/build-types/hooks/use-fixed-window-list/index.d.ts.map +1 -0
  60. package/build-types/hooks/use-focus-outside/index.d.ts +3 -3
  61. package/build-types/hooks/use-focus-outside/index.d.ts.map +1 -1
  62. package/build-types/hooks/use-focusable-iframe/index.d.ts +8 -0
  63. package/build-types/hooks/use-focusable-iframe/index.d.ts.map +1 -0
  64. package/build-types/hooks/use-previous/index.d.ts +2 -4
  65. package/build-types/hooks/use-previous/index.d.ts.map +1 -1
  66. package/build-types/hooks/use-reduced-motion/index.d.ts +5 -0
  67. package/build-types/hooks/use-reduced-motion/index.d.ts.map +1 -1
  68. package/build-types/hooks/use-throttle/index.d.ts +2 -2
  69. package/build-types/hooks/use-throttle/index.d.ts.map +1 -1
  70. package/build-types/hooks/use-viewport-match/index.d.ts +2 -2
  71. package/build-types/hooks/use-viewport-match/index.d.ts.map +1 -1
  72. package/build-types/index.d.ts +2 -0
  73. package/package.json +9 -9
  74. package/src/higher-order/if-condition/index.tsx +0 -1
  75. package/src/higher-order/pure/index.tsx +0 -1
  76. package/src/higher-order/with-instance-id/index.tsx +0 -1
  77. package/src/higher-order/with-safe-timeout/index.tsx +0 -1
  78. package/src/hooks/use-constrained-tabbing/index.js +39 -33
  79. package/src/hooks/use-debounce/index.js +1 -1
  80. package/src/hooks/use-drop-zone/index.js +11 -9
  81. package/src/hooks/use-fixed-window-list/index.js +174 -0
  82. package/src/hooks/use-focusable-iframe/README.md +29 -0
  83. package/src/hooks/use-focusable-iframe/index.js +34 -0
  84. package/src/hooks/use-previous/index.ts +24 -0
  85. package/src/hooks/use-reduced-motion/index.js +2 -13
  86. package/src/hooks/use-throttle/index.js +1 -1
  87. package/src/index.js +2 -0
  88. package/tsconfig.tsbuildinfo +1 -1694
  89. package/src/hooks/use-previous/index.js +0 -31
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/compose",
3
- "version": "5.0.1",
3
+ "version": "5.0.5",
4
4
  "description": "WordPress higher-order components (HOCs).",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -30,15 +30,15 @@
30
30
  "sideEffects": false,
31
31
  "dependencies": {
32
32
  "@babel/runtime": "^7.13.10",
33
- "@types/lodash": "4.14.149",
33
+ "@types/lodash": "^4.14.172",
34
34
  "@types/mousetrap": "^1.6.8",
35
- "@wordpress/deprecated": "^3.2.1",
36
- "@wordpress/dom": "^3.2.2",
37
- "@wordpress/element": "^4.0.0",
35
+ "@wordpress/deprecated": "^3.2.2",
36
+ "@wordpress/dom": "^3.2.6",
37
+ "@wordpress/element": "^4.0.3",
38
38
  "@wordpress/is-shallow-equal": "^4.2.0",
39
- "@wordpress/keycodes": "^3.2.1",
40
- "@wordpress/priority-queue": "^2.2.1",
41
- "clipboard": "^2.0.1",
39
+ "@wordpress/keycodes": "^3.2.3",
40
+ "@wordpress/priority-queue": "^2.2.2",
41
+ "clipboard": "^2.0.8",
42
42
  "lodash": "^4.17.21",
43
43
  "mousetrap": "^1.6.5",
44
44
  "react-resize-aware": "^3.1.0",
@@ -47,5 +47,5 @@
47
47
  "publishConfig": {
48
48
  "access": "public"
49
49
  },
50
- "gitHead": "8b67fbd424bc67f81c2d825877f0fae726d6363a"
50
+ "gitHead": "393c2b5533837fd637e998d23f0124c081a10df0"
51
51
  }
@@ -2,7 +2,6 @@
2
2
  * Internal dependencies
3
3
  */
4
4
  import createHigherOrderComponent from '../../utils/create-higher-order-component';
5
- // eslint-disable-next-line no-duplicate-imports
6
5
  import type { HigherOrderComponent } from '../../utils/create-higher-order-component';
7
6
 
8
7
  /**
@@ -8,7 +8,6 @@ import { Component } from '@wordpress/element';
8
8
  * Internal dependencies
9
9
  */
10
10
  import createHigherOrderComponent from '../../utils/create-higher-order-component';
11
- // eslint-disable-next-line no-duplicate-imports
12
11
  import type { SimpleHigherOrderComponent } from '../../utils/create-higher-order-component';
13
12
 
14
13
  /**
@@ -8,7 +8,6 @@ import type { ComponentType } from 'react';
8
8
  * Internal dependencies
9
9
  */
10
10
  import createHigherOrderComponent from '../../utils/create-higher-order-component';
11
- // eslint-disable-next-line no-duplicate-imports
12
11
  import type { PropInjectingHigherOrderComponent } from '../../utils/create-higher-order-component';
13
12
  import useInstanceId from '../../hooks/use-instance-id';
14
13
 
@@ -14,7 +14,6 @@ import { Component } from '@wordpress/element';
14
14
  * Internal dependencies
15
15
  */
16
16
  import createHigherOrderComponent from '../../utils/create-higher-order-component';
17
- // eslint-disable-next-line no-duplicate-imports
18
17
  import type { PropInjectingHigherOrderComponent } from '../../utils/create-higher-order-component';
19
18
 
20
19
  /**
@@ -3,7 +3,11 @@
3
3
  */
4
4
  import { TAB } from '@wordpress/keycodes';
5
5
  import { focus } from '@wordpress/dom';
6
- import { useCallback } from '@wordpress/element';
6
+
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ import useRefEffect from '../use-ref-effect';
7
11
 
8
12
  /**
9
13
  * In Dialogs/modals, the tabbing must be constrained to the content of
@@ -27,46 +31,48 @@ import { useCallback } from '@wordpress/element';
27
31
  * ```
28
32
  */
29
33
  function useConstrainedTabbing() {
30
- const ref = useCallback( ( /** @type {Element} */ node ) => {
31
- if ( ! node ) {
32
- return;
33
- }
34
- node.addEventListener( 'keydown', ( /** @type {Event} */ event ) => {
35
- if ( ! ( event instanceof window.KeyboardEvent ) ) {
36
- return;
37
- }
34
+ return useRefEffect( ( /** @type {HTMLElement} */ node ) => {
35
+ /** @type {number|undefined} */
36
+ let timeoutId;
37
+
38
+ function onKeyDown( /** @type {KeyboardEvent} */ event ) {
39
+ const { keyCode, shiftKey, target } = event;
38
40
 
39
- if ( event.keyCode !== TAB ) {
41
+ if ( keyCode !== TAB ) {
40
42
  return;
41
43
  }
42
44
 
43
- const tabbables = focus.tabbable.find( node );
44
- if ( ! tabbables.length ) {
45
+ const action = shiftKey ? 'findPrevious' : 'findNext';
46
+ const nextElement =
47
+ focus.tabbable[ action ](
48
+ /** @type {HTMLElement} */ ( target )
49
+ ) || null;
50
+
51
+ // If the element that is about to receive focus is outside the
52
+ // area, move focus to a div and insert it at the start or end of
53
+ // the area, depending on the direction. Without preventing default
54
+ // behaviour, the browser will then move focus to the next element.
55
+ if ( node.contains( nextElement ) ) {
45
56
  return;
46
57
  }
47
- const firstTabbable = tabbables[ 0 ];
48
- const lastTabbable = tabbables[ tabbables.length - 1 ];
49
58
 
50
- if ( event.shiftKey && event.target === firstTabbable ) {
51
- event.preventDefault();
52
- /** @type {HTMLElement} */ ( lastTabbable ).focus();
53
- } else if ( ! event.shiftKey && event.target === lastTabbable ) {
54
- event.preventDefault();
55
- /** @type {HTMLElement} */ ( firstTabbable ).focus();
56
- /*
57
- * When pressing Tab and none of the tabbables has focus, the keydown
58
- * event happens on the wrapper div: move focus on the first tabbable.
59
- */
60
- } else if (
61
- ! tabbables.includes( /** @type {Element} */ ( event.target ) )
62
- ) {
63
- event.preventDefault();
64
- /** @type {HTMLElement} */ ( firstTabbable ).focus();
65
- }
66
- } );
67
- }, [] );
59
+ const domAction = shiftKey ? 'append' : 'prepend';
60
+ const { ownerDocument } = node;
61
+ const trap = ownerDocument.createElement( 'div' );
68
62
 
69
- return ref;
63
+ trap.tabIndex = -1;
64
+ node[ domAction ]( trap );
65
+ trap.focus();
66
+ // Remove after the browser moves focus to the next element.
67
+ timeoutId = setTimeout( () => node.removeChild( trap ) );
68
+ }
69
+
70
+ node.addEventListener( 'keydown', onKeyDown );
71
+ return () => {
72
+ node.removeEventListener( 'keydown', onKeyDown );
73
+ clearTimeout( timeoutId );
74
+ };
75
+ }, [] );
70
76
  }
71
77
 
72
78
  export default useConstrainedTabbing;
@@ -23,7 +23,7 @@ import { useEffect } from '@wordpress/element';
23
23
  * @param {TFunc} fn The function to debounce.
24
24
  * @param {number} [wait] The number of milliseconds to delay.
25
25
  * @param {import('lodash').DebounceSettings} [options] The options object.
26
- * @return {TFunc & import('lodash').Cancelable} Debounced function.
26
+ * @return {import('lodash').DebouncedFunc<TFunc>} Debounced function.
27
27
  */
28
28
  export default function useDebounce( fn, wait, options ) {
29
29
  /* eslint-enable jsdoc/valid-types */
@@ -73,18 +73,24 @@ export default function useDropZone( {
73
73
  /**
74
74
  * Checks if an element is in the drop zone.
75
75
  *
76
- * @param {HTMLElement|null} elementToCheck
76
+ * @param {EventTarget|null} targetToCheck
77
77
  *
78
78
  * @return {boolean} True if in drop zone, false if not.
79
79
  */
80
- function isElementInZone( elementToCheck ) {
80
+ function isElementInZone( targetToCheck ) {
81
+ const { defaultView } = ownerDocument;
81
82
  if (
82
- ! elementToCheck ||
83
- ! element.contains( elementToCheck )
83
+ ! targetToCheck ||
84
+ ! defaultView ||
85
+ ! ( targetToCheck instanceof defaultView.HTMLElement ) ||
86
+ ! element.contains( targetToCheck )
84
87
  ) {
85
88
  return false;
86
89
  }
87
90
 
91
+ /** @type {HTMLElement|null} */
92
+ let elementToCheck = targetToCheck;
93
+
88
94
  do {
89
95
  if ( elementToCheck.dataset.isDropZone ) {
90
96
  return elementToCheck === element;
@@ -155,11 +161,7 @@ export default function useDropZone( {
155
161
  // leaving the drop zone, which means the `relatedTarget`
156
162
  // (element that has been entered) should be outside the drop
157
163
  // zone.
158
- if (
159
- isElementInZone(
160
- /** @type {HTMLElement|null} */ ( event.relatedTarget )
161
- )
162
- ) {
164
+ if ( isElementInZone( event.relatedTarget ) ) {
163
165
  return;
164
166
  }
165
167
 
@@ -0,0 +1,174 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { debounce } from 'lodash';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { useState, useLayoutEffect } from '@wordpress/element';
10
+ import { getScrollContainer } from '@wordpress/dom';
11
+ import { PAGEUP, PAGEDOWN, HOME, END } from '@wordpress/keycodes';
12
+
13
+ const DEFAULT_INIT_WINDOW_SIZE = 30;
14
+
15
+ /**
16
+ * @typedef {Object} WPFixedWindowList
17
+ *
18
+ * @property {number} visibleItems Items visible in the current viewport
19
+ * @property {number} start Start index of the window
20
+ * @property {number} end End index of the window
21
+ * @property {(index:number)=>boolean} itemInView Returns true if item is in the window
22
+ */
23
+
24
+ /**
25
+ * @typedef {Object} WPFixedWindowListOptions
26
+ *
27
+ * @property {number} [windowOverscan] Renders windowOverscan number of items before and after the calculated visible window.
28
+ * @property {boolean} [useWindowing] When false avoids calculating the window size
29
+ * @property {number} [initWindowSize] Initial window size to use on first render before we can calculate the window size.
30
+ */
31
+
32
+ /**
33
+ *
34
+ * @param {import('react').RefObject<HTMLElement>} elementRef Used to find the closest scroll container that contains element.
35
+ * @param { number } itemHeight Fixed item height in pixels
36
+ * @param { number } totalItems Total items in list
37
+ * @param { WPFixedWindowListOptions } [options] Options object
38
+ * @return {[ WPFixedWindowList, setFixedListWindow:(nextWindow:WPFixedWindowList)=>void]} Array with the fixed window list and setter
39
+ */
40
+ export default function useFixedWindowList(
41
+ elementRef,
42
+ itemHeight,
43
+ totalItems,
44
+ options
45
+ ) {
46
+ const initWindowSize = options?.initWindowSize ?? DEFAULT_INIT_WINDOW_SIZE;
47
+ const useWindowing = options?.useWindowing ?? true;
48
+
49
+ const [ fixedListWindow, setFixedListWindow ] = useState( {
50
+ visibleItems: initWindowSize,
51
+ start: 0,
52
+ end: initWindowSize,
53
+ itemInView: ( /** @type {number} */ index ) => {
54
+ return index >= 0 && index <= initWindowSize;
55
+ },
56
+ } );
57
+
58
+ useLayoutEffect( () => {
59
+ if ( ! useWindowing ) {
60
+ return;
61
+ }
62
+ const scrollContainer = getScrollContainer( elementRef.current );
63
+ const measureWindow = (
64
+ /** @type {boolean | undefined} */ initRender
65
+ ) => {
66
+ if ( ! scrollContainer ) {
67
+ return;
68
+ }
69
+ const visibleItems = Math.ceil(
70
+ scrollContainer.clientHeight / itemHeight
71
+ );
72
+ // Aim to keep opening list view fast, afterward we can optimize for scrolling
73
+ const windowOverscan = initRender
74
+ ? visibleItems
75
+ : options?.windowOverscan ?? visibleItems;
76
+ const firstViewableIndex = Math.floor(
77
+ scrollContainer.scrollTop / itemHeight
78
+ );
79
+ const start = Math.max( 0, firstViewableIndex - windowOverscan );
80
+ const end = Math.min(
81
+ totalItems - 1,
82
+ firstViewableIndex + visibleItems + windowOverscan
83
+ );
84
+ setFixedListWindow( ( lastWindow ) => {
85
+ const nextWindow = {
86
+ visibleItems,
87
+ start,
88
+ end,
89
+ itemInView: ( /** @type {number} */ index ) => {
90
+ return start <= index && index <= end;
91
+ },
92
+ };
93
+ if (
94
+ lastWindow.start !== nextWindow.start ||
95
+ lastWindow.end !== nextWindow.end ||
96
+ lastWindow.visibleItems !== nextWindow.visibleItems
97
+ ) {
98
+ return nextWindow;
99
+ }
100
+ return lastWindow;
101
+ } );
102
+ };
103
+
104
+ measureWindow( true );
105
+ const debounceMeasureList = debounce( () => {
106
+ measureWindow();
107
+ }, 16 );
108
+ scrollContainer?.addEventListener( 'scroll', debounceMeasureList );
109
+ scrollContainer?.ownerDocument?.defaultView?.addEventListener(
110
+ 'resize',
111
+ debounceMeasureList
112
+ );
113
+ scrollContainer?.ownerDocument?.defaultView?.addEventListener(
114
+ 'resize',
115
+ debounceMeasureList
116
+ );
117
+
118
+ return () => {
119
+ scrollContainer?.removeEventListener(
120
+ 'scroll',
121
+ debounceMeasureList
122
+ );
123
+ scrollContainer?.ownerDocument?.defaultView?.removeEventListener(
124
+ 'resize',
125
+ debounceMeasureList
126
+ );
127
+ };
128
+ }, [ itemHeight, elementRef, totalItems ] );
129
+
130
+ useLayoutEffect( () => {
131
+ if ( ! useWindowing ) {
132
+ return;
133
+ }
134
+ const scrollContainer = getScrollContainer( elementRef.current );
135
+ const handleKeyDown = ( /** @type {KeyboardEvent} */ event ) => {
136
+ switch ( event.keyCode ) {
137
+ case HOME: {
138
+ return scrollContainer?.scrollTo( { top: 0 } );
139
+ }
140
+ case END: {
141
+ return scrollContainer?.scrollTo( {
142
+ top: totalItems * itemHeight,
143
+ } );
144
+ }
145
+ case PAGEUP: {
146
+ return scrollContainer?.scrollTo( {
147
+ top:
148
+ scrollContainer.scrollTop -
149
+ fixedListWindow.visibleItems * itemHeight,
150
+ } );
151
+ }
152
+ case PAGEDOWN: {
153
+ return scrollContainer?.scrollTo( {
154
+ top:
155
+ scrollContainer.scrollTop +
156
+ fixedListWindow.visibleItems * itemHeight,
157
+ } );
158
+ }
159
+ }
160
+ };
161
+ scrollContainer?.ownerDocument?.defaultView?.addEventListener(
162
+ 'keydown',
163
+ handleKeyDown
164
+ );
165
+ return () => {
166
+ scrollContainer?.ownerDocument?.defaultView?.removeEventListener(
167
+ 'keydown',
168
+ handleKeyDown
169
+ );
170
+ };
171
+ }, [ totalItems, itemHeight, elementRef, fixedListWindow.visibleItems ] );
172
+
173
+ return [ fixedListWindow, setFixedListWindow ];
174
+ }
@@ -0,0 +1,29 @@
1
+ # useFocusableIframe
2
+
3
+ By default, it is not possible to detect when an iframe is focused or clicked
4
+ within. This hook uses a technique which checks whether the target of a window
5
+ `blur` event is the iframe, inferring that this has resulted in the focus of the
6
+ iframe. It dispatches an emulated
7
+ [`FocusEvent`](https://developer.mozilla.org/en-US/docs/Web/API/FocusEvent) on
8
+ the iframe element with event bubbling, so a parent component binding its own
9
+ `onFocus` event will account for focus transitioning within the iframe.
10
+
11
+ ## Usage
12
+
13
+ Use with an `iframe`. You may pass `onFocus` directly as the callback to be
14
+ invoked when the iframe receives focus, or on an ancestor component since the
15
+ event will bubble.
16
+
17
+ ```jsx
18
+ import { useFocusableIframe } from '@wordpress/compose';
19
+
20
+ const MyFocusableIframe = () => {
21
+ return(
22
+ <iframe
23
+ ref={ useFocusableIframe() }
24
+ src="/my-iframe-url"
25
+ onFocus={ () => console.log( 'iframe is focused' ) }
26
+ />
27
+ );
28
+ };
29
+ ```
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import useRefEffect from '../use-ref-effect';
5
+
6
+ /**
7
+ * Dispatches a bubbling focus event when the iframe receives focus. Use
8
+ * `onFocus` as usual on the iframe or a parent element.
9
+ *
10
+ * @return {Object} Ref to pass to the iframe.
11
+ */
12
+ export default function useFocusableIframe() {
13
+ return useRefEffect( ( element ) => {
14
+ const { ownerDocument } = element;
15
+ if ( ! ownerDocument ) return;
16
+ const { defaultView } = ownerDocument;
17
+ if ( ! defaultView ) return;
18
+
19
+ /**
20
+ * Checks whether the iframe is the activeElement, inferring that it has
21
+ * then received focus, and dispatches a focus event.
22
+ */
23
+ function checkFocus() {
24
+ if ( ownerDocument && ownerDocument.activeElement === element ) {
25
+ /** @type {HTMLElement} */ ( element ).focus();
26
+ }
27
+ }
28
+
29
+ defaultView.addEventListener( 'blur', checkFocus );
30
+ return () => {
31
+ defaultView.removeEventListener( 'blur', checkFocus );
32
+ };
33
+ }, [] );
34
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useEffect, useRef } from '@wordpress/element';
5
+
6
+ /**
7
+ * Use something's value from the previous render.
8
+ * Based on https://usehooks.com/usePrevious/.
9
+ *
10
+ * @param value The value to track.
11
+ *
12
+ * @return The value from the previous render.
13
+ */
14
+ export default function usePrevious< T >( value: T ): T | undefined {
15
+ const ref = useRef< T >();
16
+
17
+ // Store current value in ref.
18
+ useEffect( () => {
19
+ ref.current = value;
20
+ }, [ value ] ); // Re-run when value changes.
21
+
22
+ // Return previous value (happens before update in useEffect above).
23
+ return ref.current;
24
+ }
@@ -3,23 +3,12 @@
3
3
  */
4
4
  import useMediaQuery from '../use-media-query';
5
5
 
6
- /**
7
- * Whether or not the user agent is Internet Explorer.
8
- *
9
- * @type {boolean}
10
- */
11
- const IS_IE =
12
- typeof window !== 'undefined' &&
13
- window.navigator.userAgent.indexOf( 'Trident' ) >= 0;
14
-
15
6
  /**
16
7
  * Hook returning whether the user has a preference for reduced motion.
17
8
  *
18
9
  * @return {boolean} Reduced motion preference value.
19
10
  */
20
- const useReducedMotion =
21
- process.env.FORCE_REDUCED_MOTION || IS_IE
22
- ? () => true
23
- : () => useMediaQuery( '(prefers-reduced-motion: reduce)' );
11
+ const useReducedMotion = () =>
12
+ useMediaQuery( '(prefers-reduced-motion: reduce)' );
24
13
 
25
14
  export default useReducedMotion;
@@ -22,7 +22,7 @@ import { useEffect } from '@wordpress/element';
22
22
  * @param {TFunc} fn The function to throttle.
23
23
  * @param {number} [wait] The number of milliseconds to throttle invocations to.
24
24
  * @param {import('lodash').ThrottleSettings} [options] The options object. See linked documentation for details.
25
- * @return {TFunc & import('lodash').Cancelable} Throttled function.
25
+ * @return {import('lodash').DebouncedFunc<TFunc>} Throttled function.
26
26
  */
27
27
  export default function useThrottle( fn, wait, options ) {
28
28
  const throttled = useMemoOne( () => throttle( fn, wait, options ), [
package/src/index.js CHANGED
@@ -36,3 +36,5 @@ export { default as useThrottle } from './hooks/use-throttle';
36
36
  export { default as useMergeRefs } from './hooks/use-merge-refs';
37
37
  export { default as useRefEffect } from './hooks/use-ref-effect';
38
38
  export { default as __experimentalUseDropZone } from './hooks/use-drop-zone';
39
+ export { default as useFocusableIframe } from './hooks/use-focusable-iframe';
40
+ export { default as __experimentalUseFixedWindowList } from './hooks/use-fixed-window-list';