@wordpress/compose 8.1.0 → 8.1.2-next.v.202606191442.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 (148) hide show
  1. package/CHANGELOG.md +20 -1
  2. package/README.md +46 -42
  3. package/build/higher-order/pure/index.cjs +15 -0
  4. package/build/higher-order/pure/index.cjs.map +3 -3
  5. package/build/hooks/use-constrained-tabbing/index.cjs +3 -9
  6. package/build/hooks/use-constrained-tabbing/index.cjs.map +3 -3
  7. package/build/hooks/use-debounce/index.cjs +1 -1
  8. package/build/hooks/use-debounce/index.cjs.map +3 -3
  9. package/build/hooks/use-disabled/index.cjs.map +2 -2
  10. package/build/hooks/use-dragging/index.cjs +27 -22
  11. package/build/hooks/use-dragging/index.cjs.map +4 -4
  12. package/build/hooks/use-dragging/types.cjs +19 -0
  13. package/build/hooks/use-dragging/types.cjs.map +7 -0
  14. package/build/hooks/use-drop-zone/index.cjs +2 -5
  15. package/build/hooks/use-drop-zone/index.cjs.map +3 -3
  16. package/build/hooks/use-drop-zone/types.cjs +19 -0
  17. package/build/hooks/use-drop-zone/types.cjs.map +7 -0
  18. package/build/hooks/use-fixed-window-list/index.cjs +10 -8
  19. package/build/hooks/use-fixed-window-list/index.cjs.map +3 -3
  20. package/build/hooks/use-focus-return/index.cjs +12 -9
  21. package/build/hooks/use-focus-return/index.cjs.map +3 -3
  22. package/build/hooks/use-isomorphic-layout-effect/index.cjs +1 -1
  23. package/build/hooks/use-isomorphic-layout-effect/index.cjs.map +1 -1
  24. package/build/hooks/use-keyboard-shortcut/index.cjs +1 -4
  25. package/build/hooks/use-keyboard-shortcut/index.cjs.map +3 -3
  26. package/build/hooks/use-media-query/index.cjs +2 -2
  27. package/build/hooks/use-media-query/index.cjs.map +2 -2
  28. package/build/hooks/use-merge-refs/index.cjs +28 -8
  29. package/build/hooks/use-merge-refs/index.cjs.map +2 -2
  30. package/build/hooks/use-reduced-motion/index.cjs +1 -1
  31. package/build/hooks/use-reduced-motion/index.cjs.map +2 -2
  32. package/build/hooks/use-throttle/index.cjs +1 -1
  33. package/build/hooks/use-throttle/index.cjs.map +3 -3
  34. package/build/hooks/use-viewport-match/index.cjs +3 -6
  35. package/build/hooks/use-viewport-match/index.cjs.map +3 -3
  36. package/build/hooks/use-warn-on-change/index.cjs +3 -10
  37. package/build/hooks/use-warn-on-change/index.cjs.map +3 -3
  38. package/build/utils/subscribe-delegated-listener/index.cjs.map +1 -1
  39. package/build-module/higher-order/pure/index.mjs +5 -0
  40. package/build-module/higher-order/pure/index.mjs.map +2 -2
  41. package/build-module/hooks/use-constrained-tabbing/index.mjs +3 -9
  42. package/build-module/hooks/use-constrained-tabbing/index.mjs.map +3 -3
  43. package/build-module/hooks/use-debounce/index.mjs +1 -1
  44. package/build-module/hooks/use-debounce/index.mjs.map +3 -3
  45. package/build-module/hooks/use-disabled/index.mjs.map +2 -2
  46. package/build-module/hooks/use-dragging/index.mjs +27 -22
  47. package/build-module/hooks/use-dragging/index.mjs.map +4 -4
  48. package/build-module/hooks/use-dragging/types.mjs +1 -0
  49. package/build-module/hooks/use-dragging/types.mjs.map +7 -0
  50. package/build-module/hooks/use-drop-zone/index.mjs +2 -5
  51. package/build-module/hooks/use-drop-zone/index.mjs.map +3 -3
  52. package/build-module/hooks/use-drop-zone/types.mjs +1 -0
  53. package/build-module/hooks/use-drop-zone/types.mjs.map +7 -0
  54. package/build-module/hooks/use-fixed-window-list/index.mjs +10 -8
  55. package/build-module/hooks/use-fixed-window-list/index.mjs.map +3 -3
  56. package/build-module/hooks/use-focus-return/index.mjs +12 -9
  57. package/build-module/hooks/use-focus-return/index.mjs.map +3 -3
  58. package/build-module/hooks/use-isomorphic-layout-effect/index.mjs +1 -1
  59. package/build-module/hooks/use-isomorphic-layout-effect/index.mjs.map +1 -1
  60. package/build-module/hooks/use-keyboard-shortcut/index.mjs +1 -4
  61. package/build-module/hooks/use-keyboard-shortcut/index.mjs.map +3 -3
  62. package/build-module/hooks/use-media-query/index.mjs +2 -2
  63. package/build-module/hooks/use-media-query/index.mjs.map +2 -2
  64. package/build-module/hooks/use-merge-refs/index.mjs +28 -8
  65. package/build-module/hooks/use-merge-refs/index.mjs.map +2 -2
  66. package/build-module/hooks/use-reduced-motion/index.mjs +1 -1
  67. package/build-module/hooks/use-reduced-motion/index.mjs.map +2 -2
  68. package/build-module/hooks/use-throttle/index.mjs +1 -1
  69. package/build-module/hooks/use-throttle/index.mjs.map +3 -3
  70. package/build-module/hooks/use-viewport-match/index.mjs +3 -6
  71. package/build-module/hooks/use-viewport-match/index.mjs.map +3 -3
  72. package/build-module/hooks/use-warn-on-change/index.mjs +3 -10
  73. package/build-module/hooks/use-warn-on-change/index.mjs.map +3 -3
  74. package/build-module/utils/subscribe-delegated-listener/index.mjs.map +1 -1
  75. package/build-types/higher-order/pure/index.d.ts.map +1 -1
  76. package/build-types/hooks/use-constrained-tabbing/index.d.ts +2 -2
  77. package/build-types/hooks/use-constrained-tabbing/index.d.ts.map +1 -1
  78. package/build-types/hooks/use-debounce/index.d.ts +7 -6
  79. package/build-types/hooks/use-debounce/index.d.ts.map +1 -1
  80. package/build-types/hooks/use-disabled/index.d.ts +1 -1
  81. package/build-types/hooks/use-disabled/index.d.ts.map +1 -1
  82. package/build-types/hooks/use-dragging/index.d.ts +9 -13
  83. package/build-types/hooks/use-dragging/index.d.ts.map +1 -1
  84. package/build-types/hooks/use-dragging/types.d.ts +11 -0
  85. package/build-types/hooks/use-dragging/types.d.ts.map +1 -0
  86. package/build-types/hooks/use-drop-zone/index.d.ts +4 -21
  87. package/build-types/hooks/use-drop-zone/index.d.ts.map +1 -1
  88. package/build-types/hooks/use-drop-zone/types.d.ts +35 -0
  89. package/build-types/hooks/use-drop-zone/types.d.ts.map +1 -0
  90. package/build-types/hooks/use-fixed-window-list/index.d.ts +22 -26
  91. package/build-types/hooks/use-fixed-window-list/index.d.ts.map +1 -1
  92. package/build-types/hooks/use-focus-return/index.d.ts +3 -3
  93. package/build-types/hooks/use-focus-return/index.d.ts.map +1 -1
  94. package/build-types/hooks/use-isomorphic-layout-effect/index.d.ts.map +1 -1
  95. package/build-types/hooks/use-keyboard-shortcut/index.d.ts +29 -23
  96. package/build-types/hooks/use-keyboard-shortcut/index.d.ts.map +1 -1
  97. package/build-types/hooks/use-media-query/index.d.ts +1 -1
  98. package/build-types/hooks/use-media-query/index.d.ts.map +1 -1
  99. package/build-types/hooks/use-merge-refs/index.d.ts +7 -5
  100. package/build-types/hooks/use-merge-refs/index.d.ts.map +1 -1
  101. package/build-types/hooks/use-reduced-motion/index.d.ts +1 -1
  102. package/build-types/hooks/use-reduced-motion/index.d.ts.map +1 -1
  103. package/build-types/hooks/use-throttle/index.d.ts +8 -6
  104. package/build-types/hooks/use-throttle/index.d.ts.map +1 -1
  105. package/build-types/hooks/use-viewport-match/index.d.ts +3 -3
  106. package/build-types/hooks/use-viewport-match/index.d.ts.map +1 -1
  107. package/build-types/hooks/use-warn-on-change/index.d.ts +7 -7
  108. package/build-types/hooks/use-warn-on-change/index.d.ts.map +1 -1
  109. package/package.json +21 -12
  110. package/src/higher-order/pure/index.tsx +6 -0
  111. package/src/higher-order/pure/test/index.js +14 -81
  112. package/src/hooks/use-constrained-tabbing/{index.js → index.ts} +7 -11
  113. package/src/hooks/use-debounce/{index.js → index.ts} +11 -6
  114. package/src/hooks/use-disabled/index.ts +3 -1
  115. package/src/hooks/use-dragging/index.ts +78 -0
  116. package/src/hooks/use-dragging/types.ts +11 -0
  117. package/src/hooks/use-drop-zone/README.md +1 -1
  118. package/src/hooks/use-drop-zone/{index.js → index.ts} +17 -31
  119. package/src/hooks/use-drop-zone/types.ts +34 -0
  120. package/src/hooks/use-fixed-window-list/{index.js → index.ts} +46 -37
  121. package/src/hooks/use-focus-return/{index.js → index.ts} +26 -21
  122. package/src/hooks/use-keyboard-shortcut/{index.js → index.ts} +43 -28
  123. package/src/hooks/use-media-query/index.ts +10 -3
  124. package/src/hooks/use-media-query/test/ssr.js +47 -0
  125. package/src/hooks/use-merge-refs/index.ts +49 -18
  126. package/src/hooks/use-merge-refs/test/index.js +288 -0
  127. package/src/hooks/use-reduced-motion/{index.js → index.ts} +2 -2
  128. package/src/hooks/use-throttle/{index.js → index.ts} +12 -6
  129. package/src/hooks/use-viewport-match/{index.js → index.ts} +33 -26
  130. package/src/hooks/use-warn-on-change/index.ts +42 -0
  131. package/src/higher-order/with-network-connectivity/README.md +0 -20
  132. package/src/higher-order/with-network-connectivity/index.native.js +0 -19
  133. package/src/higher-order/with-preferred-color-scheme/index.native.js +0 -40
  134. package/src/hooks/use-constrained-tabbing/index.native.js +0 -14
  135. package/src/hooks/use-dragging/index.js +0 -74
  136. package/src/hooks/use-focus-outside/index.native.js +0 -170
  137. package/src/hooks/use-keyboard-shortcut/index.native.js +0 -2
  138. package/src/hooks/use-network-connectivity/index.native.js +0 -59
  139. package/src/hooks/use-network-connectivity/test/index.native.js +0 -87
  140. package/src/hooks/use-preferred-color-scheme/index.android.js +0 -30
  141. package/src/hooks/use-preferred-color-scheme/index.ios.js +0 -13
  142. package/src/hooks/use-preferred-color-scheme-style/index.native.js +0 -33
  143. package/src/hooks/use-resize-observer/index.native.js +0 -1
  144. package/src/hooks/use-resize-observer/legacy/index.native.js +0 -59
  145. package/src/hooks/use-resize-observer/legacy/test/index.native.js +0 -46
  146. package/src/hooks/use-warn-on-change/index.js +0 -43
  147. package/src/index.native.js +0 -44
  148. /package/src/hooks/use-isomorphic-layout-effect/{index.js → index.ts} +0 -0
@@ -0,0 +1,78 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useCallback, useEffect, useRef, useState } from '@wordpress/element';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import useIsomorphicLayoutEffect from '../use-isomorphic-layout-effect';
10
+ import type { DraggingProps, DraggingReturn } from './types';
11
+
12
+ /**
13
+ * Hook to manage drag events with proper event handling
14
+ *
15
+ * @param props Drag handlers
16
+ * @param props.onDragStart
17
+ * @param props.onDragMove
18
+ * @param props.onDragEnd
19
+ * @return Drag state and handlers
20
+ */
21
+ export default function useDragging( {
22
+ onDragStart,
23
+ onDragMove,
24
+ onDragEnd,
25
+ }: DraggingProps ): DraggingReturn {
26
+ const [ isDragging, setIsDragging ] = useState( false );
27
+
28
+ const eventsRef = useRef< DraggingProps >( {
29
+ onDragStart,
30
+ onDragMove,
31
+ onDragEnd,
32
+ } );
33
+ useIsomorphicLayoutEffect( () => {
34
+ eventsRef.current.onDragStart = onDragStart;
35
+ eventsRef.current.onDragMove = onDragMove;
36
+ eventsRef.current.onDragEnd = onDragEnd;
37
+ }, [ onDragStart, onDragMove, onDragEnd ] );
38
+
39
+ const onMouseMove = useCallback( ( event: MouseEvent ): void => {
40
+ eventsRef.current.onDragMove?.( event );
41
+ }, [] );
42
+
43
+ const endDrag = useCallback(
44
+ function endDrag( event?: MouseEvent ): void {
45
+ eventsRef.current.onDragEnd?.( event );
46
+ document.removeEventListener( 'mousemove', onMouseMove );
47
+ document.removeEventListener( 'mouseup', endDrag );
48
+ setIsDragging( false );
49
+ },
50
+ [ onMouseMove ]
51
+ );
52
+
53
+ const startDrag = useCallback(
54
+ ( event: React.MouseEvent ): void => {
55
+ eventsRef.current.onDragStart?.( event );
56
+ document.addEventListener( 'mousemove', onMouseMove );
57
+ document.addEventListener( 'mouseup', endDrag );
58
+ setIsDragging( true );
59
+ },
60
+ [ onMouseMove, endDrag ]
61
+ );
62
+
63
+ // Remove the global events when unmounting if needed.
64
+ useEffect( () => {
65
+ return () => {
66
+ if ( isDragging ) {
67
+ document.removeEventListener( 'mousemove', onMouseMove );
68
+ document.removeEventListener( 'mouseup', endDrag );
69
+ }
70
+ };
71
+ }, [ isDragging, onMouseMove, endDrag ] );
72
+
73
+ return {
74
+ startDrag,
75
+ endDrag,
76
+ isDragging,
77
+ };
78
+ }
@@ -0,0 +1,11 @@
1
+ export interface DraggingProps {
2
+ onDragStart?: ( e: React.MouseEvent ) => void;
3
+ onDragMove?: ( e: MouseEvent ) => void;
4
+ onDragEnd?: ( e?: MouseEvent ) => void;
5
+ }
6
+
7
+ export interface DraggingReturn {
8
+ startDrag: ( e: React.MouseEvent ) => void;
9
+ endDrag: ( e?: MouseEvent ) => void;
10
+ isDragging: boolean;
11
+ }
@@ -2,7 +2,7 @@
2
2
 
3
3
  A hook to facilitate drag and drop handling within a designated drop zone area. An optional `dropZoneElement` can be provided, however by default the drop zone is bound by the area where the returned `ref` is assigned.
4
4
 
5
- When using a `dropZoneElement`, it is expected that the `ref` will be attached to a node that is a descendent of the `dropZoneElement`. Additionally, the element passed to `dropZoneElement` should be stored in state rather than a plain ref to ensure reactive updating when it changes.
5
+ When using a `dropZoneElement`, it is expected that the `ref` will be attached to a node that is a descendant of the `dropZoneElement`. Additionally, the element passed to `dropZoneElement` should be stored in state rather than a plain ref to ensure reactive updating when it changes.
6
6
 
7
7
  ## Usage
8
8
 
@@ -3,21 +3,13 @@
3
3
  */
4
4
  import useRefEffect from '../use-ref-effect';
5
5
  import useEvent from '../use-event';
6
+ import type { UseDropZoneProps } from './types';
6
7
 
7
8
  /**
8
9
  * A hook to facilitate drag and drop handling.
9
10
  *
10
- * @param {Object} props Named parameters.
11
- * @param {?HTMLElement} [props.dropZoneElement] Optional element to be used as the drop zone.
12
- * @param {boolean} [props.isDisabled] Whether or not to disable the drop zone.
13
- * @param {(e: DragEvent) => void} [props.onDragStart] Called when dragging has started.
14
- * @param {(e: DragEvent) => void} [props.onDragEnter] Called when the zone is entered.
15
- * @param {(e: DragEvent) => void} [props.onDragOver] Called when the zone is moved within.
16
- * @param {(e: DragEvent) => void} [props.onDragLeave] Called when the zone is left.
17
- * @param {(e: MouseEvent) => void} [props.onDragEnd] Called when dragging has ended.
18
- * @param {(e: DragEvent) => void} [props.onDrop] Called when dropping in the zone.
19
- *
20
- * @return {React.RefCallback<HTMLElement>} Ref callback to be passed to the drop zone element.
11
+ * @param {UseDropZoneProps} props Hook options
12
+ * @return Ref callback to be passed to the drop zone element.
21
13
  */
22
14
  export default function useDropZone( {
23
15
  dropZoneElement,
@@ -28,7 +20,7 @@ export default function useDropZone( {
28
20
  onDragLeave: _onDragLeave,
29
21
  onDragEnd: _onDragEnd,
30
22
  onDragOver: _onDragOver,
31
- } ) {
23
+ }: UseDropZoneProps ): React.RefCallback< HTMLElement > {
32
24
  const onDropEvent = useEvent( _onDrop );
33
25
  const onDragStartEvent = useEvent( _onDragStart );
34
26
  const onDragEnterEvent = useEvent( _onDragEnter );
@@ -37,7 +29,7 @@ export default function useDropZone( {
37
29
  const onDragOverEvent = useEvent( _onDragOver );
38
30
 
39
31
  return useRefEffect(
40
- ( elem ) => {
32
+ ( elem: HTMLElement ) => {
41
33
  if ( isDisabled ) {
42
34
  return;
43
35
  }
@@ -58,7 +50,9 @@ export default function useDropZone( {
58
50
  *
59
51
  * @return {boolean} True if in drop zone, false if not.
60
52
  */
61
- function isElementInZone( targetToCheck ) {
53
+ function isElementInZone(
54
+ targetToCheck: EventTarget | null
55
+ ): boolean {
62
56
  const { defaultView } = ownerDocument;
63
57
 
64
58
  if (
@@ -70,8 +64,7 @@ export default function useDropZone( {
70
64
  return false;
71
65
  }
72
66
 
73
- /** @type {HTMLElement|null} */
74
- let elementToCheck = targetToCheck;
67
+ let elementToCheck: HTMLElement | null = targetToCheck;
75
68
 
76
69
  do {
77
70
  if ( elementToCheck.dataset.isDropZone ) {
@@ -82,7 +75,7 @@ export default function useDropZone( {
82
75
  return false;
83
76
  }
84
77
 
85
- function maybeDragStart( /** @type {DragEvent} */ event ) {
78
+ function maybeDragStart( event: DragEvent ): void {
86
79
  if ( isDragging ) {
87
80
  return;
88
81
  }
@@ -101,18 +94,14 @@ export default function useDropZone( {
101
94
  }
102
95
  }
103
96
 
104
- function onDragEnter( /** @type {DragEvent} */ event ) {
97
+ function onDragEnter( event: DragEvent ): void {
105
98
  event.preventDefault();
106
99
 
107
100
  // The `dragenter` event will also fire when entering child
108
101
  // elements, but we only want to call `onDragEnter` when
109
102
  // entering the drop zone, which means the `relatedTarget`
110
103
  // (element that has been left) should be outside the drop zone.
111
- if (
112
- element.contains(
113
- /** @type {Node} */ ( event.relatedTarget )
114
- )
115
- ) {
104
+ if ( element.contains( event.relatedTarget as Node ) ) {
116
105
  return;
117
106
  }
118
107
 
@@ -121,18 +110,15 @@ export default function useDropZone( {
121
110
  }
122
111
  }
123
112
 
124
- function onDragOver( /** @type {DragEvent} */ event ) {
125
- // Only call onDragOver for the innermost hovered drop zones.
113
+ function onDragOver( event: DragEvent ): void {
126
114
  if ( ! event.defaultPrevented && _onDragOver ) {
127
115
  onDragOverEvent( event );
128
116
  }
129
117
 
130
- // Prevent the browser default while also signalling to parent
131
- // drop zones that `onDragOver` is already handled.
132
118
  event.preventDefault();
133
119
  }
134
120
 
135
- function onDragLeave( /** @type {DragEvent} */ event ) {
121
+ function onDragLeave( event: DragEvent ): void {
136
122
  // The `dragleave` event will also fire when leaving child
137
123
  // elements, but we only want to call `onDragLeave` when
138
124
  // leaving the drop zone, which means the `relatedTarget`
@@ -150,7 +136,7 @@ export default function useDropZone( {
150
136
  }
151
137
  }
152
138
 
153
- function onDrop( /** @type {DragEvent} */ event ) {
139
+ function onDrop( event: DragEvent ): void {
154
140
  // Don't handle drop if an inner drop zone already handled it.
155
141
  if ( event.defaultPrevented ) {
156
142
  return;
@@ -173,7 +159,7 @@ export default function useDropZone( {
173
159
  maybeDragEnd( event );
174
160
  }
175
161
 
176
- function maybeDragEnd( /** @type {MouseEvent} */ event ) {
162
+ function maybeDragEnd( event: Event ): void {
177
163
  if ( ! isDragging ) {
178
164
  return;
179
165
  }
@@ -184,7 +170,7 @@ export default function useDropZone( {
184
170
  ownerDocument.removeEventListener( 'mousemove', maybeDragEnd );
185
171
 
186
172
  if ( _onDragEnd ) {
187
- onDragEndEvent( event );
173
+ onDragEndEvent( event as MouseEvent );
188
174
  }
189
175
  }
190
176
 
@@ -0,0 +1,34 @@
1
+ export interface UseDropZoneProps {
2
+ /**
3
+ * Optional element to be used as the drop zone.
4
+ */
5
+ dropZoneElement?: HTMLElement | null;
6
+ /**
7
+ * Whether or not to disable the drop zone.
8
+ */
9
+ isDisabled?: boolean;
10
+ /**
11
+ * Called when dragging has started.
12
+ */
13
+ onDragStart?: ( e: DragEvent ) => void;
14
+ /**
15
+ * Called when the zone is entered.
16
+ */
17
+ onDragEnter?: ( e: DragEvent ) => void;
18
+ /**
19
+ * Called when the zone is moved within.
20
+ */
21
+ onDragOver?: ( e: DragEvent ) => void;
22
+ /**
23
+ * Called when the zone is left.
24
+ */
25
+ onDragLeave?: ( e: DragEvent ) => void;
26
+ /**
27
+ * Called when dragging has ended.
28
+ */
29
+ onDragEnd?: ( e: MouseEvent ) => void;
30
+ /**
31
+ * Called when dropping in the zone.
32
+ */
33
+ onDrop?: ( e: DragEvent ) => void;
34
+ }
@@ -12,49 +12,58 @@ import { debounce } from '../../utils/debounce';
12
12
 
13
13
  const DEFAULT_INIT_WINDOW_SIZE = 30;
14
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
- */
15
+ interface FixedWindowList {
16
+ /** Items visible in the current viewport */
17
+ visibleItems: number;
18
+ /** Start index of the window */
19
+ start: number;
20
+ /** End index of the window */
21
+ end: number;
22
+ /** Returns true if item is in the window */
23
+ itemInView: ( index: number ) => boolean;
24
+ }
23
25
 
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
- * @property {any} [expandedState] Used to recalculate the window size when the expanded state of a list changes.
31
- */
26
+ interface FixedWindowListOptions {
27
+ /** Renders windowOverscan number of items before and after the calculated visible window. */
28
+ windowOverscan?: number;
29
+ /** When false avoids calculating the window size */
30
+ useWindowing?: boolean;
31
+ /** Initial window size to use on first render before we can calculate the window size. */
32
+ initWindowSize?: number;
33
+ /** Used to recalculate the window size when the expanded state of a list changes. */
34
+ expandedState?: any;
35
+ }
32
36
 
33
37
  /**
34
38
  *
35
- * @param {React.RefObject<HTMLElement>} elementRef Used to find the closest scroll container that contains element.
36
- * @param { number } itemHeight Fixed item height in pixels
37
- * @param { number } totalItems Total items in list
38
- * @param { WPFixedWindowListOptions } [options] Options object
39
- * @return {[ WPFixedWindowList, setFixedListWindow:(nextWindow:WPFixedWindowList)=>void]} Array with the fixed window list and setter
39
+ * @param elementRef Used to find the closest scroll container that contains element.
40
+ * @param itemHeight Fixed item height in pixels
41
+ * @param totalItems Total items in list
42
+ * @param [options] Options object
43
+ * @return Array with the fixed window list and setter
40
44
  */
41
45
  export default function useFixedWindowList(
42
- elementRef,
43
- itemHeight,
44
- totalItems,
45
- options
46
- ) {
46
+ elementRef: React.RefObject< HTMLElement >,
47
+ itemHeight: number,
48
+ totalItems: number,
49
+ options?: FixedWindowListOptions
50
+ ): [
51
+ FixedWindowList,
52
+ React.Dispatch< React.SetStateAction< FixedWindowList > >,
53
+ ] {
47
54
  const initWindowSize = options?.initWindowSize ?? DEFAULT_INIT_WINDOW_SIZE;
48
55
  const useWindowing = options?.useWindowing ?? true;
49
56
 
50
- const [ fixedListWindow, setFixedListWindow ] = useState( {
51
- visibleItems: initWindowSize,
52
- start: 0,
53
- end: initWindowSize,
54
- itemInView: ( /** @type {number} */ index ) => {
55
- return index >= 0 && index <= initWindowSize;
56
- },
57
- } );
57
+ const [ fixedListWindow, setFixedListWindow ] = useState< FixedWindowList >(
58
+ {
59
+ visibleItems: initWindowSize,
60
+ start: 0,
61
+ end: initWindowSize,
62
+ itemInView: ( index: number ) => {
63
+ return index >= 0 && index <= initWindowSize;
64
+ },
65
+ }
66
+ );
58
67
 
59
68
  useLayoutEffect( () => {
60
69
  if ( ! useWindowing ) {
@@ -67,7 +76,7 @@ export default function useFixedWindowList(
67
76
  * @param {boolean} [initRender] Indicates if this is the initial render
68
77
  * @return {void}
69
78
  */
70
- const measureWindow = ( initRender ) => {
79
+ const measureWindow = ( initRender?: boolean ) => {
71
80
  if ( ! scrollContainer ) {
72
81
  return;
73
82
  }
@@ -91,7 +100,7 @@ export default function useFixedWindowList(
91
100
  visibleItems,
92
101
  start,
93
102
  end,
94
- itemInView: ( /** @type {number} */ index ) => {
103
+ itemInView: ( index: number ) => {
95
104
  return start <= index && index <= end;
96
105
  },
97
106
  };
@@ -144,7 +153,7 @@ export default function useFixedWindowList(
144
153
  return;
145
154
  }
146
155
  const scrollContainer = getScrollContainer( elementRef.current );
147
- const handleKeyDown = ( /** @type {KeyboardEvent} */ event ) => {
156
+ const handleKeyDown = ( event: KeyboardEvent ) => {
148
157
  switch ( event.keyCode ) {
149
158
  case HOME: {
150
159
  return scrollContainer?.scrollTo( { top: 0 } );
@@ -3,18 +3,17 @@
3
3
  */
4
4
  import { useRef, useEffect, useCallback } from '@wordpress/element';
5
5
 
6
- /** @type {Element|null} */
7
- let origin = null;
6
+ let origin: Element | null = null;
8
7
 
9
8
  /**
10
9
  * Adds the unmount behavior of returning focus to the element which had it
11
10
  * previously as is expected for roles like menus or dialogs.
12
11
  *
13
- * @param {() => void} [onFocusReturn] Overrides the default return behavior.
14
- * @return {React.RefCallback<HTMLElement>} Element Ref.
12
+ * @param onFocusReturn Overrides the default return behavior.
13
+ * @return Element Ref.
15
14
  *
16
15
  * @example
17
- * ```js
16
+ * ```ts
18
17
  * import { useFocusReturn } from '@wordpress/compose';
19
18
  *
20
19
  * const WithFocusReturn = () => {
@@ -28,23 +27,26 @@ let origin = null;
28
27
  * }
29
28
  * ```
30
29
  */
31
- function useFocusReturn( onFocusReturn ) {
32
- /** @type {React.MutableRefObject<null | HTMLElement>} */
33
- const ref = useRef( null );
34
- /** @type {React.MutableRefObject<null | Element>} */
35
- const focusedBeforeMount = useRef( null );
36
- const onFocusReturnRef = useRef( onFocusReturn );
30
+ function useFocusReturn(
31
+ onFocusReturn?: () => void
32
+ ): React.RefCallback< HTMLElement > {
33
+ const ref = useRef< HTMLElement | null >( null );
34
+ const focusedBeforeMountRef = useRef< Element | null >( null );
35
+ const onFocusReturnRef = useRef< ( () => void ) | undefined >(
36
+ onFocusReturn
37
+ );
38
+
37
39
  useEffect( () => {
38
40
  onFocusReturnRef.current = onFocusReturn;
39
41
  }, [ onFocusReturn ] );
40
42
 
41
- return useCallback( ( node ) => {
43
+ return useCallback( ( node: HTMLElement | null ) => {
42
44
  if ( node ) {
43
45
  // Set ref to be used when unmounting.
44
46
  ref.current = node;
45
47
 
46
48
  // Only set when the node mounts.
47
- if ( focusedBeforeMount.current ) {
49
+ if ( focusedBeforeMountRef.current ) {
48
50
  return;
49
51
  }
50
52
 
@@ -54,14 +56,15 @@ function useFocusReturn( onFocusReturn ) {
54
56
  ? node.ownerDocument.activeElement.contentDocument
55
57
  : node.ownerDocument;
56
58
 
57
- focusedBeforeMount.current = activeDocument?.activeElement ?? null;
58
- } else if ( focusedBeforeMount.current ) {
59
+ focusedBeforeMountRef.current =
60
+ activeDocument?.activeElement ?? null;
61
+ } else if ( focusedBeforeMountRef.current ) {
59
62
  const isFocused = ref.current?.contains(
60
- ref.current?.ownerDocument.activeElement
63
+ ref.current?.ownerDocument.activeElement ?? null
61
64
  );
62
65
 
63
66
  if ( ref.current?.isConnected && ! isFocused ) {
64
- origin ??= focusedBeforeMount.current;
67
+ origin ??= focusedBeforeMountRef.current;
65
68
  return;
66
69
  }
67
70
 
@@ -72,11 +75,13 @@ function useFocusReturn( onFocusReturn ) {
72
75
  if ( onFocusReturnRef.current ) {
73
76
  onFocusReturnRef.current();
74
77
  } else {
75
- /** @type {null|HTMLElement} */ (
76
- ! focusedBeforeMount.current.isConnected
78
+ const elementToFocus = (
79
+ ! focusedBeforeMountRef.current.isConnected
77
80
  ? origin
78
- : focusedBeforeMount.current
79
- )?.focus();
81
+ : focusedBeforeMountRef.current
82
+ ) as HTMLElement | SVGElement | null;
83
+
84
+ elementToFocus?.focus();
80
85
  }
81
86
  origin = null;
82
87
  }
@@ -3,44 +3,59 @@
3
3
  */
4
4
  import Mousetrap from 'mousetrap';
5
5
  import 'mousetrap/plugins/global-bind/mousetrap-global-bind.js';
6
+ import type { ExtendedKeyboardEvent } from 'mousetrap';
6
7
 
7
8
  /**
8
9
  * WordPress dependencies
9
10
  */
11
+ import type { RefObject } from '@wordpress/element';
10
12
  import { useEffect, useRef } from '@wordpress/element';
11
13
  import { isAppleOS } from '@wordpress/keycodes';
12
14
 
13
- /**
14
- * A block selection object.
15
- *
16
- * @typedef {Object} WPKeyboardShortcutConfig
17
- *
18
- * @property {boolean} [bindGlobal] Handle keyboard events anywhere including inside textarea/input fields.
19
- * @property {string} [eventName] Event name used to trigger the handler, defaults to keydown.
20
- * @property {boolean} [isDisabled] Disables the keyboard handler if the value is true.
21
- * @property {React.RefObject<HTMLElement | null>} [target] React reference to the DOM element used to catch the keyboard event.
22
- */
15
+ type KeyboardShortcutConfig = {
16
+ /**
17
+ * Handle keyboard events anywhere including inside textarea/input fields.
18
+ */
19
+ bindGlobal: boolean;
20
+ /**
21
+ * Event name used to trigger the handler, defaults to keydown.
22
+ */
23
+ eventName: string;
24
+ /**
25
+ * Disables the keyboard handler if the value is true.
26
+ */
27
+ isDisabled: boolean;
28
+ /**
29
+ * React reference to the DOM element used to catch the keyboard event.
30
+ */
31
+ target: RefObject< HTMLElement >;
32
+ };
23
33
 
24
34
  /**
25
35
  * Attach a keyboard shortcut handler.
26
36
  *
27
37
  * @see https://craig.is/killing/mice#api.bind for information about the `callback` parameter.
28
38
  *
29
- * @param {string[]|string} shortcuts Keyboard Shortcuts.
30
- * @param {(e: Mousetrap.ExtendedKeyboardEvent, combo: string) => void} callback Shortcut callback.
31
- * @param {WPKeyboardShortcutConfig} options Shortcut options.
39
+ * @param shortcuts Keyboard Shortcuts.
40
+ * @param callback Shortcut callback.
41
+ * @param options Shortcut options.
42
+ * @param options.bindGlobal
43
+ * @param options.eventName
44
+ * @param options.isDisabled
45
+ * @param options.target
32
46
  */
33
47
  function useKeyboardShortcut(
34
- shortcuts,
35
- callback,
48
+ shortcuts: string[] | string,
49
+ callback: ( e: ExtendedKeyboardEvent, combo: string ) => void,
36
50
  {
37
51
  bindGlobal = false,
38
52
  eventName = 'keydown',
39
- isDisabled = false, // This is important for performance considerations.
53
+ isDisabled = false,
40
54
  target,
41
- } = {}
55
+ }: Partial< KeyboardShortcutConfig > = {}
42
56
  ) {
43
57
  const currentCallbackRef = useRef( callback );
58
+
44
59
  useEffect( () => {
45
60
  currentCallbackRef.current = callback;
46
61
  }, [ callback ] );
@@ -49,29 +64,28 @@ function useKeyboardShortcut(
49
64
  if ( isDisabled ) {
50
65
  return;
51
66
  }
67
+
52
68
  const mousetrap = new Mousetrap(
53
69
  target && target.current
54
70
  ? target.current
55
71
  : // We were passing `document` here previously, so to successfully cast it to Element we must cast it first to `unknown`.
56
72
  // Not sure if this is a mistake but it was the behavior previous to the addition of types so we're just doing what's
57
73
  // necessary to maintain the existing behavior.
58
- /** @type {Element} */ ( /** @type {unknown} */ ( document ) )
74
+ ( document as unknown as Element )
59
75
  );
76
+
60
77
  const shortcutsArray = Array.isArray( shortcuts )
61
78
  ? shortcuts
62
79
  : [ shortcuts ];
63
- shortcutsArray.forEach( ( shortcut ) => {
80
+
81
+ shortcutsArray.forEach( ( shortcut: string ) => {
64
82
  const keys = shortcut.split( '+' );
65
- // Determines whether a key is a modifier by the length of the string.
66
- // E.g. if I add a pass a shortcut Shift+Cmd+M, it'll determine that
67
- // the modifiers are Shift and Cmd because they're not a single character.
68
83
  const modifiers = new Set(
69
84
  keys.filter( ( value ) => value.length > 1 )
70
85
  );
71
86
  const hasAlt = modifiers.has( 'alt' );
72
87
  const hasShift = modifiers.has( 'shift' );
73
88
 
74
- // This should be better moved to the shortcut registration instead.
75
89
  if (
76
90
  isAppleOS() &&
77
91
  ( ( modifiers.size === 1 && hasAlt ) ||
@@ -83,12 +97,13 @@ function useKeyboardShortcut(
83
97
  }
84
98
 
85
99
  const bindFn = bindGlobal ? 'bindGlobal' : 'bind';
86
- // @ts-ignore `bindGlobal` is an undocumented property
87
- mousetrap[ bindFn ](
100
+ // `@ts-expect-error` Mousetrap typings don’t include `bindGlobal`
101
+ // It exists at runtime via the plugin
102
+ // `any` is used here to allow dynamic access via `bindFn`
103
+ ( mousetrap as any )[ bindFn ](
88
104
  shortcut,
89
- (
90
- /** @type {[e: import('mousetrap').ExtendedKeyboardEvent, combo: string]} */ ...args
91
- ) => currentCallbackRef.current( ...args ),
105
+ ( ...args: [ Mousetrap.ExtendedKeyboardEvent, string ] ) =>
106
+ currentCallbackRef.current( ...args ),
92
107
  eventName
93
108
  );
94
109
  } );
@@ -19,8 +19,11 @@ const EMPTY_SUBSCRIBER: MQLSubscriber = {
19
19
  getValue: () => false,
20
20
  };
21
21
 
22
- function getMQLSubscriber( view: Window, query?: string ): MQLSubscriber {
23
- if ( ! query || typeof view?.matchMedia !== 'function' ) {
22
+ function getMQLSubscriber(
23
+ view: Window | undefined,
24
+ query?: string
25
+ ): MQLSubscriber {
26
+ if ( ! view || ! query || typeof view.matchMedia !== 'function' ) {
24
27
  return EMPTY_SUBSCRIBER;
25
28
  }
26
29
 
@@ -75,7 +78,11 @@ function getMQLSubscriber( view: Window, query?: string ): MQLSubscriber {
75
78
  */
76
79
  export default function useMediaQuery(
77
80
  query?: string,
78
- view: Window = window
81
+ // Resolve the default lazily so SSR (where `window` is undeclared) does not
82
+ // throw a ReferenceError when this default expression is evaluated.
83
+ view: Window | undefined = typeof window !== 'undefined'
84
+ ? window
85
+ : undefined
79
86
  ): boolean {
80
87
  const source = getMQLSubscriber( view, query );
81
88