@wordpress/compose 7.40.1-next.v.202602271551.0 → 7.40.1

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 (64) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +11 -9
  3. package/build/hooks/use-copy-on-click/index.cjs +43 -18
  4. package/build/hooks/use-copy-on-click/index.cjs.map +4 -4
  5. package/build/hooks/use-copy-to-clipboard/index.cjs +58 -12
  6. package/build/hooks/use-copy-to-clipboard/index.cjs.map +4 -4
  7. package/build/hooks/use-dialog/index.cjs +2 -2
  8. package/build/hooks/use-dialog/index.cjs.map +3 -3
  9. package/build/hooks/use-focus-on-mount/index.cjs +15 -13
  10. package/build/hooks/use-focus-on-mount/index.cjs.map +3 -3
  11. package/build/hooks/use-media-query/index.cjs +12 -9
  12. package/build/hooks/use-media-query/index.cjs.map +3 -3
  13. package/build/hooks/use-viewport-match/index.cjs +2 -2
  14. package/build/hooks/use-viewport-match/index.cjs.map +2 -2
  15. package/build/index.cjs +2 -2
  16. package/build/index.cjs.map +2 -2
  17. package/build-module/hooks/use-copy-on-click/index.mjs +44 -19
  18. package/build-module/hooks/use-copy-on-click/index.mjs.map +3 -3
  19. package/build-module/hooks/use-copy-to-clipboard/index.mjs +53 -12
  20. package/build-module/hooks/use-copy-to-clipboard/index.mjs.map +3 -3
  21. package/build-module/hooks/use-dialog/index.mjs +1 -1
  22. package/build-module/hooks/use-dialog/index.mjs.map +2 -2
  23. package/build-module/hooks/use-focus-on-mount/index.mjs +15 -9
  24. package/build-module/hooks/use-focus-on-mount/index.mjs.map +3 -3
  25. package/build-module/hooks/use-media-query/index.mjs +12 -9
  26. package/build-module/hooks/use-media-query/index.mjs.map +3 -3
  27. package/build-module/hooks/use-viewport-match/index.mjs +2 -2
  28. package/build-module/hooks/use-viewport-match/index.mjs.map +2 -2
  29. package/build-module/index.mjs +46 -46
  30. package/build-module/index.mjs.map +2 -2
  31. package/build-types/hooks/use-copy-on-click/index.d.ts +8 -9
  32. package/build-types/hooks/use-copy-on-click/index.d.ts.map +1 -1
  33. package/build-types/hooks/use-copy-to-clipboard/index.d.ts +22 -6
  34. package/build-types/hooks/use-copy-to-clipboard/index.d.ts.map +1 -1
  35. package/build-types/hooks/use-dialog/index.d.ts +6 -9
  36. package/build-types/hooks/use-dialog/index.d.ts.map +1 -1
  37. package/build-types/hooks/use-focus-on-mount/index.d.ts +4 -10
  38. package/build-types/hooks/use-focus-on-mount/index.d.ts.map +1 -1
  39. package/build-types/hooks/use-isomorphic-layout-effect/index.d.ts +2 -2
  40. package/build-types/hooks/use-isomorphic-layout-effect/index.d.ts.map +1 -1
  41. package/build-types/hooks/use-media-query/index.d.ts +4 -3
  42. package/build-types/hooks/use-media-query/index.d.ts.map +1 -1
  43. package/build-types/hooks/use-viewport-match/index.d.ts +2 -1
  44. package/build-types/hooks/use-viewport-match/index.d.ts.map +1 -1
  45. package/build-types/index.d.ts +1 -1
  46. package/build-types/lock-unlock.d.ts +2 -0
  47. package/build-types/lock-unlock.d.ts.map +1 -0
  48. package/build-types/private-apis.d.ts +5 -0
  49. package/build-types/private-apis.d.ts.map +1 -0
  50. package/build-types/utils/subscribe-delegated-listener/index.d.ts +27 -0
  51. package/build-types/utils/subscribe-delegated-listener/index.d.ts.map +1 -0
  52. package/package.json +9 -10
  53. package/src/hooks/use-copy-on-click/index.ts +101 -0
  54. package/src/hooks/use-copy-on-click/test/index.tsx +162 -0
  55. package/src/hooks/use-copy-to-clipboard/index.ts +120 -0
  56. package/src/hooks/use-copy-to-clipboard/test/index.tsx +144 -0
  57. package/src/hooks/use-dialog/index.ts +6 -9
  58. package/src/hooks/use-focus-on-mount/{index.ts → index.js} +34 -23
  59. package/src/hooks/use-media-query/{index.js → index.ts} +27 -16
  60. package/src/hooks/use-viewport-match/index.js +3 -2
  61. package/src/hooks/use-viewport-match/test/index.js +32 -10
  62. package/src/index.js +1 -1
  63. package/src/hooks/use-copy-on-click/index.js +0 -75
  64. package/src/hooks/use-copy-to-clipboard/index.js +0 -69
package/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ### New Features
6
+
7
+ - Hooks `useMediaQuery` and `useViewportMatch` accept a new optional `view` argument of type `Window`, which enables consumers to perform media queries in a window other than the global one (e.g. an iframe) ([#76446](https://github.com/WordPress/gutenberg/pull/76446)).
8
+
5
9
  ## 7.40.0 (2026-02-18)
6
10
 
7
11
  ## 7.39.0 (2026-01-29)
package/README.md CHANGED
@@ -220,9 +220,9 @@ Copies the text to the clipboard when the element is clicked.
220
220
 
221
221
  _Parameters_
222
222
 
223
- - _ref_ `React.RefObject<string | Element | NodeListOf<Element>>`: Reference with the element.
224
- - _text_ `string|Function`: The text to copy.
225
- - _timeout_ `[number]`: Optional timeout to reset the returned state. 4 seconds by default.
223
+ - _ref_ `RefObject< string | Element | NodeListOf< Element > >`: Reference with the element.
224
+ - _text_ `string | ( () => string )`: The text to copy.
225
+ - _timeout_ `number`: Optional timeout to reset the returned state. 4 seconds by default.
226
226
 
227
227
  _Returns_
228
228
 
@@ -234,12 +234,12 @@ Copies the given text to the clipboard when the element is clicked.
234
234
 
235
235
  _Parameters_
236
236
 
237
- - _text_ `string | (() => string)`: The text to copy. Use a function if not already available and expensive to compute.
238
- - _onSuccess_ `Function`: Called when to text is copied.
237
+ - _text_ `string | ( () => string )`: The text to copy. Use a function if not already available and expensive to compute.
238
+ - _onSuccess_ `() => void`: Called when to text is copied.
239
239
 
240
240
  _Returns_
241
241
 
242
- - `React.Ref<TElementType>`: A ref to assign to the target element.
242
+ - `RefCallback< T >`: A ref to assign to the target element.
243
243
 
244
244
  ### useDebounce
245
245
 
@@ -338,7 +338,7 @@ _Returns_
338
338
 
339
339
  ### useFocusOnMount
340
340
 
341
- Determines focus behavior when the element mounts.
341
+ Hook used to focus the first tabbable element on mount.
342
342
 
343
343
  _Usage_
344
344
 
@@ -358,11 +358,11 @@ const WithFocusOnMount = () => {
358
358
 
359
359
  _Parameters_
360
360
 
361
- - _focusOnMount_ `useFocusOnMount.Mode`: Behavioral mode. Defaults to `"firstElement"` which focuses the first tabbable element within; `"firstInputElement"` focuses the first value control within; `true` focuses the element itself; `false` does nothing.
361
+ - _focusOnMount_ `boolean | 'firstElement' | 'firstInputElement'`: Focus on mount mode.
362
362
 
363
363
  _Returns_
364
364
 
365
- - Ref callback.
365
+ - `React.RefCallback<HTMLElement>`: Ref callback.
366
366
 
367
367
  ### useFocusReturn
368
368
 
@@ -431,6 +431,7 @@ Runs a media query and returns its value when it changes.
431
431
  _Parameters_
432
432
 
433
433
  - _query_ `[string]`: Media Query.
434
+ - _view_ `[Window]`: Window instance, else default to global window
434
435
 
435
436
  _Returns_
436
437
 
@@ -592,6 +593,7 @@ _Parameters_
592
593
 
593
594
  - _breakpoint_ `WPBreakpoint`: Breakpoint size name.
594
595
  - _operator_ `[WPViewportOperator]`: Viewport operator.
596
+ - _view_ `[Window]`: Window instance in which to perform viewport matching.
595
597
 
596
598
  _Returns_
597
599
 
@@ -27,48 +27,73 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
27
  ));
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
 
30
- // packages/compose/src/hooks/use-copy-on-click/index.js
30
+ // packages/compose/src/hooks/use-copy-on-click/index.ts
31
31
  var use_copy_on_click_exports = {};
32
32
  __export(use_copy_on_click_exports, {
33
33
  default: () => useCopyOnClick
34
34
  });
35
35
  module.exports = __toCommonJS(use_copy_on_click_exports);
36
- var import_clipboard = __toESM(require("clipboard"));
37
36
  var import_element = require("@wordpress/element");
38
37
  var import_deprecated = __toESM(require("@wordpress/deprecated"));
38
+ var import_use_copy_to_clipboard = require("../use-copy-to-clipboard/index.cjs");
39
39
  function useCopyOnClick(ref, text, timeout = 4e3) {
40
40
  (0, import_deprecated.default)("wp.compose.useCopyOnClick", {
41
41
  since: "5.8",
42
42
  alternative: "wp.compose.useCopyToClipboard"
43
43
  });
44
- const clipboardRef = (0, import_element.useRef)(void 0);
45
44
  const [hasCopied, setHasCopied] = (0, import_element.useState)(false);
46
45
  (0, import_element.useEffect)(() => {
46
+ let isActive = true;
47
47
  let timeoutId;
48
48
  if (!ref.current) {
49
49
  return;
50
50
  }
51
- clipboardRef.current = new import_clipboard.default(ref.current, {
52
- text: () => typeof text === "function" ? text() : text
53
- });
54
- clipboardRef.current.on("success", ({ clearSelection, trigger }) => {
55
- clearSelection();
56
- if (trigger) {
57
- trigger.focus();
51
+ let targets;
52
+ if (typeof ref.current === "string") {
53
+ targets = typeof document !== "undefined" ? Array.from(document.querySelectorAll(ref.current)) : [];
54
+ } else if ("length" in ref.current && typeof ref.current.length === "number") {
55
+ targets = Array.from(ref.current);
56
+ } else {
57
+ targets = [ref.current];
58
+ }
59
+ if (targets.length === 0) {
60
+ return;
61
+ }
62
+ const handleClick = async (event) => {
63
+ const trigger = event.currentTarget;
64
+ if (!trigger) {
65
+ return;
58
66
  }
59
- if (timeout) {
60
- setHasCopied(true);
61
- clearTimeout(timeoutId);
62
- timeoutId = setTimeout(() => setHasCopied(false), timeout);
67
+ const success = await (0, import_use_copy_to_clipboard.copyToClipboard)(
68
+ typeof text === "function" ? text() : text || "",
69
+ trigger
70
+ );
71
+ if (!isActive) {
72
+ return;
63
73
  }
64
- });
74
+ if (success) {
75
+ (0, import_use_copy_to_clipboard.clearSelection)(trigger);
76
+ if (timeout) {
77
+ setHasCopied(true);
78
+ clearTimeout(timeoutId);
79
+ timeoutId = setTimeout(
80
+ () => setHasCopied(false),
81
+ timeout
82
+ );
83
+ }
84
+ }
85
+ };
86
+ for (const target of targets) {
87
+ target.addEventListener("click", handleClick);
88
+ }
65
89
  return () => {
66
- if (clipboardRef.current) {
67
- clipboardRef.current.destroy();
90
+ isActive = false;
91
+ for (const target of targets) {
92
+ target.removeEventListener("click", handleClick);
68
93
  }
69
94
  clearTimeout(timeoutId);
70
95
  };
71
- }, [text, timeout, setHasCopied]);
96
+ }, [ref, text, timeout]);
72
97
  return hasCopied;
73
98
  }
74
99
  //# sourceMappingURL=index.cjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../../src/hooks/use-copy-on-click/index.js"],
4
- "sourcesContent": ["/**\n * External dependencies\n */\nimport Clipboard from 'clipboard';\n\n/**\n * WordPress dependencies\n */\nimport { useRef, useEffect, useState } from '@wordpress/element';\nimport deprecated from '@wordpress/deprecated';\n\n/**\n * Copies the text to the clipboard when the element is clicked.\n *\n * @deprecated\n *\n * @param {React.RefObject<string | Element | NodeListOf<Element>>} ref Reference with the element.\n * @param {string|Function} text The text to copy.\n * @param {number} [timeout] Optional timeout to reset the returned\n * state. 4 seconds by default.\n *\n * @return {boolean} Whether or not the text has been copied. Resets after the\n * timeout.\n */\nexport default function useCopyOnClick( ref, text, timeout = 4000 ) {\n\tdeprecated( 'wp.compose.useCopyOnClick', {\n\t\tsince: '5.8',\n\t\talternative: 'wp.compose.useCopyToClipboard',\n\t} );\n\n\t/** @type {React.MutableRefObject<Clipboard | undefined>} */\n\tconst clipboardRef = useRef( undefined );\n\tconst [ hasCopied, setHasCopied ] = useState( false );\n\n\tuseEffect( () => {\n\t\t/** @type {number | undefined} */\n\t\tlet timeoutId;\n\n\t\tif ( ! ref.current ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Clipboard listens to click events.\n\t\tclipboardRef.current = new Clipboard( ref.current, {\n\t\t\ttext: () => ( typeof text === 'function' ? text() : text ),\n\t\t} );\n\n\t\tclipboardRef.current.on( 'success', ( { clearSelection, trigger } ) => {\n\t\t\t// Clearing selection will move focus back to the triggering button,\n\t\t\t// ensuring that it is not reset to the body, and further that it is\n\t\t\t// kept within the rendered node.\n\t\t\tclearSelection();\n\n\t\t\t// Handle ClipboardJS focus bug, see https://github.com/zenorocha/clipboard.js/issues/680\n\t\t\tif ( trigger ) {\n\t\t\t\t/** @type {HTMLElement} */ ( trigger ).focus();\n\t\t\t}\n\n\t\t\tif ( timeout ) {\n\t\t\t\tsetHasCopied( true );\n\t\t\t\tclearTimeout( timeoutId );\n\t\t\t\ttimeoutId = setTimeout( () => setHasCopied( false ), timeout );\n\t\t\t}\n\t\t} );\n\n\t\treturn () => {\n\t\t\tif ( clipboardRef.current ) {\n\t\t\t\tclipboardRef.current.destroy();\n\t\t\t}\n\t\t\tclearTimeout( timeoutId );\n\t\t};\n\t}, [ text, timeout, setHasCopied ] );\n\n\treturn hasCopied;\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,uBAAsB;AAKtB,qBAA4C;AAC5C,wBAAuB;AAeR,SAAR,eAAiC,KAAK,MAAM,UAAU,KAAO;AACnE,wBAAAA,SAAY,6BAA6B;AAAA,IACxC,OAAO;AAAA,IACP,aAAa;AAAA,EACd,CAAE;AAGF,QAAM,mBAAe,uBAAQ,MAAU;AACvC,QAAM,CAAE,WAAW,YAAa,QAAI,yBAAU,KAAM;AAEpD,gCAAW,MAAM;AAEhB,QAAI;AAEJ,QAAK,CAAE,IAAI,SAAU;AACpB;AAAA,IACD;AAGA,iBAAa,UAAU,IAAI,iBAAAC,QAAW,IAAI,SAAS;AAAA,MAClD,MAAM,MAAQ,OAAO,SAAS,aAAa,KAAK,IAAI;AAAA,IACrD,CAAE;AAEF,iBAAa,QAAQ,GAAI,WAAW,CAAE,EAAE,gBAAgB,QAAQ,MAAO;AAItE,qBAAe;AAGf,UAAK,SAAU;AACa,QAAE,QAAU,MAAM;AAAA,MAC9C;AAEA,UAAK,SAAU;AACd,qBAAc,IAAK;AACnB,qBAAc,SAAU;AACxB,oBAAY,WAAY,MAAM,aAAc,KAAM,GAAG,OAAQ;AAAA,MAC9D;AAAA,IACD,CAAE;AAEF,WAAO,MAAM;AACZ,UAAK,aAAa,SAAU;AAC3B,qBAAa,QAAQ,QAAQ;AAAA,MAC9B;AACA,mBAAc,SAAU;AAAA,IACzB;AAAA,EACD,GAAG,CAAE,MAAM,SAAS,YAAa,CAAE;AAEnC,SAAO;AACR;",
6
- "names": ["deprecated", "Clipboard"]
3
+ "sources": ["../../../src/hooks/use-copy-on-click/index.ts"],
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useEffect, useState } from '@wordpress/element';\nimport deprecated from '@wordpress/deprecated';\nimport type { RefObject } from 'react';\n\n/**\n * Internal dependencies\n */\nimport { clearSelection, copyToClipboard } from '../use-copy-to-clipboard';\n\n/**\n * Copies the text to the clipboard when the element is clicked.\n *\n * @deprecated\n * @param ref Reference with the element.\n * @param text The text to copy.\n * @param timeout Optional timeout to reset the returned\n * state. 4 seconds by default.\n * @return Whether or not the text has been copied. Resets after the\n * timeout.\n */\nexport default function useCopyOnClick(\n\tref: RefObject< string | Element | NodeListOf< Element > >,\n\ttext: string | ( () => string ),\n\ttimeout: number = 4000\n): boolean {\n\tdeprecated( 'wp.compose.useCopyOnClick', {\n\t\tsince: '5.8',\n\t\talternative: 'wp.compose.useCopyToClipboard',\n\t} );\n\n\tconst [ hasCopied, setHasCopied ] = useState( false );\n\n\tuseEffect( () => {\n\t\t// Flag to prevent state updates after unmount when the Promise resolves.\n\t\tlet isActive = true;\n\t\tlet timeoutId: ReturnType< typeof setTimeout > | undefined;\n\t\tif ( ! ref.current ) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet targets: Element[];\n\t\tif ( typeof ref.current === 'string' ) {\n\t\t\ttargets =\n\t\t\t\ttypeof document !== 'undefined'\n\t\t\t\t\t? Array.from( document.querySelectorAll( ref.current ) )\n\t\t\t\t\t: [];\n\t\t} else if (\n\t\t\t'length' in ref.current &&\n\t\t\ttypeof ref.current.length === 'number'\n\t\t) {\n\t\t\ttargets = Array.from( ref.current );\n\t\t} else {\n\t\t\ttargets = [ ref.current as Element ];\n\t\t}\n\n\t\tif ( targets.length === 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst handleClick = async ( event: Event ) => {\n\t\t\tconst trigger = event.currentTarget as Element;\n\t\t\tif ( ! trigger ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst success = await copyToClipboard(\n\t\t\t\ttypeof text === 'function' ? text() : text || '',\n\t\t\t\ttrigger\n\t\t\t);\n\t\t\tif ( ! isActive ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif ( success ) {\n\t\t\t\tclearSelection( trigger );\n\t\t\t\tif ( timeout ) {\n\t\t\t\t\tsetHasCopied( true );\n\t\t\t\t\tclearTimeout( timeoutId );\n\t\t\t\t\ttimeoutId = setTimeout(\n\t\t\t\t\t\t() => setHasCopied( false ),\n\t\t\t\t\t\ttimeout\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tfor ( const target of targets ) {\n\t\t\ttarget.addEventListener( 'click', handleClick );\n\t\t}\n\t\treturn () => {\n\t\t\tisActive = false;\n\t\t\tfor ( const target of targets ) {\n\t\t\t\ttarget.removeEventListener( 'click', handleClick );\n\t\t\t}\n\t\t\tclearTimeout( timeoutId );\n\t\t};\n\t}, [ ref, text, timeout ] );\n\n\treturn hasCopied;\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,qBAAoC;AACpC,wBAAuB;AAMvB,mCAAgD;AAajC,SAAR,eACN,KACA,MACA,UAAkB,KACR;AACV,wBAAAA,SAAY,6BAA6B;AAAA,IACxC,OAAO;AAAA,IACP,aAAa;AAAA,EACd,CAAE;AAEF,QAAM,CAAE,WAAW,YAAa,QAAI,yBAAU,KAAM;AAEpD,gCAAW,MAAM;AAEhB,QAAI,WAAW;AACf,QAAI;AACJ,QAAK,CAAE,IAAI,SAAU;AACpB;AAAA,IACD;AAEA,QAAI;AACJ,QAAK,OAAO,IAAI,YAAY,UAAW;AACtC,gBACC,OAAO,aAAa,cACjB,MAAM,KAAM,SAAS,iBAAkB,IAAI,OAAQ,CAAE,IACrD,CAAC;AAAA,IACN,WACC,YAAY,IAAI,WAChB,OAAO,IAAI,QAAQ,WAAW,UAC7B;AACD,gBAAU,MAAM,KAAM,IAAI,OAAQ;AAAA,IACnC,OAAO;AACN,gBAAU,CAAE,IAAI,OAAmB;AAAA,IACpC;AAEA,QAAK,QAAQ,WAAW,GAAI;AAC3B;AAAA,IACD;AAEA,UAAM,cAAc,OAAQ,UAAkB;AAC7C,YAAM,UAAU,MAAM;AACtB,UAAK,CAAE,SAAU;AAChB;AAAA,MACD;AACA,YAAM,UAAU,UAAM;AAAA,QACrB,OAAO,SAAS,aAAa,KAAK,IAAI,QAAQ;AAAA,QAC9C;AAAA,MACD;AACA,UAAK,CAAE,UAAW;AACjB;AAAA,MACD;AACA,UAAK,SAAU;AACd,yDAAgB,OAAQ;AACxB,YAAK,SAAU;AACd,uBAAc,IAAK;AACnB,uBAAc,SAAU;AACxB,sBAAY;AAAA,YACX,MAAM,aAAc,KAAM;AAAA,YAC1B;AAAA,UACD;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAEA,eAAY,UAAU,SAAU;AAC/B,aAAO,iBAAkB,SAAS,WAAY;AAAA,IAC/C;AACA,WAAO,MAAM;AACZ,iBAAW;AACX,iBAAY,UAAU,SAAU;AAC/B,eAAO,oBAAqB,SAAS,WAAY;AAAA,MAClD;AACA,mBAAc,SAAU;AAAA,IACzB;AAAA,EACD,GAAG,CAAE,KAAK,MAAM,OAAQ,CAAE;AAE1B,SAAO;AACR;",
6
+ "names": ["deprecated"]
7
7
  }
@@ -27,15 +27,51 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
27
  ));
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
 
30
- // packages/compose/src/hooks/use-copy-to-clipboard/index.js
30
+ // packages/compose/src/hooks/use-copy-to-clipboard/index.ts
31
31
  var use_copy_to_clipboard_exports = {};
32
32
  __export(use_copy_to_clipboard_exports, {
33
+ clearSelection: () => clearSelection,
34
+ copyToClipboard: () => copyToClipboard,
33
35
  default: () => useCopyToClipboard
34
36
  });
35
37
  module.exports = __toCommonJS(use_copy_to_clipboard_exports);
36
- var import_clipboard = __toESM(require("clipboard"));
37
38
  var import_element = require("@wordpress/element");
38
39
  var import_use_ref_effect = __toESM(require("../use-ref-effect/index.cjs"));
40
+ async function copyToClipboard(text, trigger) {
41
+ if (!trigger) {
42
+ return false;
43
+ }
44
+ const { ownerDocument } = trigger;
45
+ if (!ownerDocument) {
46
+ return false;
47
+ }
48
+ const { defaultView } = ownerDocument;
49
+ try {
50
+ if (defaultView?.navigator?.clipboard?.writeText) {
51
+ await defaultView.navigator.clipboard.writeText(text);
52
+ return true;
53
+ }
54
+ const textarea = ownerDocument.createElement("textarea");
55
+ textarea.value = text;
56
+ textarea.setAttribute("readonly", "");
57
+ textarea.style.position = "fixed";
58
+ textarea.style.left = "-9999px";
59
+ textarea.style.top = "-9999px";
60
+ ownerDocument.body.appendChild(textarea);
61
+ textarea.select();
62
+ const success = ownerDocument.execCommand("copy");
63
+ textarea.remove();
64
+ return success;
65
+ } catch {
66
+ return false;
67
+ }
68
+ }
69
+ function clearSelection(trigger) {
70
+ if ("focus" in trigger && typeof trigger.focus === "function") {
71
+ trigger.focus();
72
+ }
73
+ trigger.ownerDocument?.defaultView?.getSelection()?.removeAllRanges();
74
+ }
39
75
  function useUpdatedRef(value) {
40
76
  const ref = (0, import_element.useRef)(value);
41
77
  (0, import_element.useLayoutEffect)(() => {
@@ -47,20 +83,30 @@ function useCopyToClipboard(text, onSuccess) {
47
83
  const textRef = useUpdatedRef(text);
48
84
  const onSuccessRef = useUpdatedRef(onSuccess);
49
85
  return (0, import_use_ref_effect.default)((node) => {
50
- const clipboard = new import_clipboard.default(node, {
51
- text() {
52
- return typeof textRef.current === "function" ? textRef.current() : textRef.current || "";
86
+ let isActive = true;
87
+ const handleClick = async () => {
88
+ const textToCopy = typeof textRef.current === "function" ? textRef.current() : textRef.current || "";
89
+ const success = await copyToClipboard(textToCopy, node);
90
+ if (!isActive) {
91
+ return;
53
92
  }
54
- });
55
- clipboard.on("success", ({ clearSelection }) => {
56
- clearSelection();
57
- if (onSuccessRef.current) {
58
- onSuccessRef.current();
93
+ if (success) {
94
+ clearSelection(node);
95
+ if (onSuccessRef.current) {
96
+ onSuccessRef.current();
97
+ }
59
98
  }
60
- });
99
+ };
100
+ node.addEventListener("click", handleClick);
61
101
  return () => {
62
- clipboard.destroy();
102
+ isActive = false;
103
+ node.removeEventListener("click", handleClick);
63
104
  };
64
105
  }, []);
65
106
  }
107
+ // Annotate the CommonJS export names for ESM import in node:
108
+ 0 && (module.exports = {
109
+ clearSelection,
110
+ copyToClipboard
111
+ });
66
112
  //# sourceMappingURL=index.cjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../../src/hooks/use-copy-to-clipboard/index.js"],
4
- "sourcesContent": ["/**\n * External dependencies\n */\nimport Clipboard from 'clipboard';\n\n/**\n * WordPress dependencies\n */\nimport { useRef, useLayoutEffect } from '@wordpress/element';\n\n/**\n * Internal dependencies\n */\nimport useRefEffect from '../use-ref-effect';\n\n/**\n * @template T\n * @param {T} value\n * @return {React.RefObject<T>} The updated ref\n */\nfunction useUpdatedRef( value ) {\n\tconst ref = useRef( value );\n\tuseLayoutEffect( () => {\n\t\tref.current = value;\n\t}, [ value ] );\n\treturn ref;\n}\n\n/**\n * Copies the given text to the clipboard when the element is clicked.\n *\n * @template {HTMLElement} TElementType\n * @param {string | (() => string)} text The text to copy. Use a function if not\n * already available and expensive to compute.\n * @param {Function} onSuccess Called when to text is copied.\n *\n * @return {React.Ref<TElementType>} A ref to assign to the target element.\n */\nexport default function useCopyToClipboard( text, onSuccess ) {\n\t// Store the dependencies as refs and continuously update them so they're\n\t// fresh when the callback is called.\n\tconst textRef = useUpdatedRef( text );\n\tconst onSuccessRef = useUpdatedRef( onSuccess );\n\treturn useRefEffect( ( node ) => {\n\t\t// Clipboard listens to click events.\n\t\tconst clipboard = new Clipboard( node, {\n\t\t\ttext() {\n\t\t\t\treturn typeof textRef.current === 'function'\n\t\t\t\t\t? textRef.current()\n\t\t\t\t\t: textRef.current || '';\n\t\t\t},\n\t\t} );\n\n\t\tclipboard.on( 'success', ( { clearSelection } ) => {\n\t\t\t// Clearing selection will move focus back to the triggering\n\t\t\t// button, ensuring that it is not reset to the body, and\n\t\t\t// further that it is kept within the rendered node.\n\t\t\tclearSelection();\n\n\t\t\tif ( onSuccessRef.current ) {\n\t\t\t\tonSuccessRef.current();\n\t\t\t}\n\t\t} );\n\n\t\treturn () => {\n\t\t\tclipboard.destroy();\n\t\t};\n\t}, [] );\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,uBAAsB;AAKtB,qBAAwC;AAKxC,4BAAyB;AAOzB,SAAS,cAAe,OAAQ;AAC/B,QAAM,UAAM,uBAAQ,KAAM;AAC1B,sCAAiB,MAAM;AACtB,QAAI,UAAU;AAAA,EACf,GAAG,CAAE,KAAM,CAAE;AACb,SAAO;AACR;AAYe,SAAR,mBAAqC,MAAM,WAAY;AAG7D,QAAM,UAAU,cAAe,IAAK;AACpC,QAAM,eAAe,cAAe,SAAU;AAC9C,aAAO,sBAAAA,SAAc,CAAE,SAAU;AAEhC,UAAM,YAAY,IAAI,iBAAAC,QAAW,MAAM;AAAA,MACtC,OAAO;AACN,eAAO,OAAO,QAAQ,YAAY,aAC/B,QAAQ,QAAQ,IAChB,QAAQ,WAAW;AAAA,MACvB;AAAA,IACD,CAAE;AAEF,cAAU,GAAI,WAAW,CAAE,EAAE,eAAe,MAAO;AAIlD,qBAAe;AAEf,UAAK,aAAa,SAAU;AAC3B,qBAAa,QAAQ;AAAA,MACtB;AAAA,IACD,CAAE;AAEF,WAAO,MAAM;AACZ,gBAAU,QAAQ;AAAA,IACnB;AAAA,EACD,GAAG,CAAC,CAAE;AACP;",
6
- "names": ["useRefEffect", "Clipboard"]
3
+ "sources": ["../../../src/hooks/use-copy-to-clipboard/index.ts"],
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useRef, useLayoutEffect } from '@wordpress/element';\nimport type { MutableRefObject, RefCallback } from 'react';\n\n/**\n * Internal dependencies\n */\nimport useRefEffect from '../use-ref-effect';\n\n/**\n * Copies text to the clipboard using the Clipboard API when available,\n * with a fallback for non-secure contexts (e.g. HTTP) and older browsers.\n *\n * @param text The text to copy.\n * @param trigger The element that triggered the copy.\n * @return Resolves to true if successful, false otherwise.\n */\nexport async function copyToClipboard(\n\ttext: string,\n\ttrigger: Element | null\n): Promise< boolean > {\n\tif ( ! trigger ) {\n\t\treturn false;\n\t}\n\tconst { ownerDocument } = trigger;\n\tif ( ! ownerDocument ) {\n\t\treturn false;\n\t}\n\tconst { defaultView } = ownerDocument;\n\ttry {\n\t\tif ( defaultView?.navigator?.clipboard?.writeText ) {\n\t\t\tawait defaultView.navigator.clipboard.writeText( text );\n\t\t\treturn true;\n\t\t}\n\t\t// Fallback for non-secure contexts (HTTP) and older browsers.\n\t\tconst textarea = ownerDocument.createElement( 'textarea' );\n\t\ttextarea.value = text;\n\t\ttextarea.setAttribute( 'readonly', '' );\n\t\ttextarea.style.position = 'fixed';\n\t\ttextarea.style.left = '-9999px';\n\t\ttextarea.style.top = '-9999px';\n\t\townerDocument.body.appendChild( textarea );\n\t\ttextarea.select();\n\t\tconst success = ownerDocument.execCommand( 'copy' );\n\t\ttextarea.remove();\n\t\treturn success;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Clears the current selection and restores focus to the trigger element.\n *\n * @param trigger The element that triggered the copy.\n */\nexport function clearSelection( trigger: Element ): void {\n\tif ( 'focus' in trigger && typeof trigger.focus === 'function' ) {\n\t\ttrigger.focus();\n\t}\n\ttrigger.ownerDocument?.defaultView?.getSelection()?.removeAllRanges();\n}\n\n/**\n * @template T\n * @param value\n * @return A ref to assign to the target element.\n */\nfunction useUpdatedRef< T >( value: T ): MutableRefObject< T > {\n\tconst ref = useRef< T >( value );\n\tuseLayoutEffect( () => {\n\t\tref.current = value;\n\t}, [ value ] );\n\treturn ref;\n}\n\n/**\n * Copies the given text to the clipboard when the element is clicked.\n *\n * @template T\n * @param text The text to copy. Use a function if not\n * already available and expensive to compute.\n * @param onSuccess Called when to text is copied.\n *\n * @return A ref to assign to the target element.\n */\nexport default function useCopyToClipboard< T extends HTMLElement >(\n\ttext: string | ( () => string ),\n\tonSuccess?: () => void\n): RefCallback< T > {\n\tconst textRef = useUpdatedRef( text );\n\tconst onSuccessRef = useUpdatedRef( onSuccess );\n\treturn useRefEffect( ( node ) => {\n\t\t// Flag to prevent callbacks after unmount when the Promise resolves.\n\t\tlet isActive = true;\n\t\tconst handleClick = async () => {\n\t\t\tconst textToCopy =\n\t\t\t\ttypeof textRef.current === 'function'\n\t\t\t\t\t? textRef.current()\n\t\t\t\t\t: textRef.current || '';\n\t\t\tconst success = await copyToClipboard( textToCopy, node );\n\t\t\tif ( ! isActive ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif ( success ) {\n\t\t\t\tclearSelection( node );\n\t\t\t\tif ( onSuccessRef.current ) {\n\t\t\t\t\tonSuccessRef.current();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tnode.addEventListener( 'click', handleClick );\n\t\treturn () => {\n\t\t\tisActive = false;\n\t\t\tnode.removeEventListener( 'click', handleClick );\n\t\t};\n\t}, [] );\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,qBAAwC;AAMxC,4BAAyB;AAUzB,eAAsB,gBACrB,MACA,SACqB;AACrB,MAAK,CAAE,SAAU;AAChB,WAAO;AAAA,EACR;AACA,QAAM,EAAE,cAAc,IAAI;AAC1B,MAAK,CAAE,eAAgB;AACtB,WAAO;AAAA,EACR;AACA,QAAM,EAAE,YAAY,IAAI;AACxB,MAAI;AACH,QAAK,aAAa,WAAW,WAAW,WAAY;AACnD,YAAM,YAAY,UAAU,UAAU,UAAW,IAAK;AACtD,aAAO;AAAA,IACR;AAEA,UAAM,WAAW,cAAc,cAAe,UAAW;AACzD,aAAS,QAAQ;AACjB,aAAS,aAAc,YAAY,EAAG;AACtC,aAAS,MAAM,WAAW;AAC1B,aAAS,MAAM,OAAO;AACtB,aAAS,MAAM,MAAM;AACrB,kBAAc,KAAK,YAAa,QAAS;AACzC,aAAS,OAAO;AAChB,UAAM,UAAU,cAAc,YAAa,MAAO;AAClD,aAAS,OAAO;AAChB,WAAO;AAAA,EACR,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAOO,SAAS,eAAgB,SAAyB;AACxD,MAAK,WAAW,WAAW,OAAO,QAAQ,UAAU,YAAa;AAChE,YAAQ,MAAM;AAAA,EACf;AACA,UAAQ,eAAe,aAAa,aAAa,GAAG,gBAAgB;AACrE;AAOA,SAAS,cAAoB,OAAkC;AAC9D,QAAM,UAAM,uBAAa,KAAM;AAC/B,sCAAiB,MAAM;AACtB,QAAI,UAAU;AAAA,EACf,GAAG,CAAE,KAAM,CAAE;AACb,SAAO;AACR;AAYe,SAAR,mBACN,MACA,WACmB;AACnB,QAAM,UAAU,cAAe,IAAK;AACpC,QAAM,eAAe,cAAe,SAAU;AAC9C,aAAO,sBAAAA,SAAc,CAAE,SAAU;AAEhC,QAAI,WAAW;AACf,UAAM,cAAc,YAAY;AAC/B,YAAM,aACL,OAAO,QAAQ,YAAY,aACxB,QAAQ,QAAQ,IAChB,QAAQ,WAAW;AACvB,YAAM,UAAU,MAAM,gBAAiB,YAAY,IAAK;AACxD,UAAK,CAAE,UAAW;AACjB;AAAA,MACD;AACA,UAAK,SAAU;AACd,uBAAgB,IAAK;AACrB,YAAK,aAAa,SAAU;AAC3B,uBAAa,QAAQ;AAAA,QACtB;AAAA,MACD;AAAA,IACD;AACA,SAAK,iBAAkB,SAAS,WAAY;AAC5C,WAAO,MAAM;AACZ,iBAAW;AACX,WAAK,oBAAqB,SAAS,WAAY;AAAA,IAChD;AAAA,EACD,GAAG,CAAC,CAAE;AACP;",
6
+ "names": ["useRefEffect"]
7
7
  }
@@ -36,7 +36,7 @@ module.exports = __toCommonJS(use_dialog_exports);
36
36
  var import_element = require("@wordpress/element");
37
37
  var import_keycodes = require("@wordpress/keycodes");
38
38
  var import_use_constrained_tabbing = __toESM(require("../use-constrained-tabbing/index.cjs"));
39
- var import_use_focus_on_mount = require("../use-focus-on-mount/index.cjs");
39
+ var import_use_focus_on_mount = __toESM(require("../use-focus-on-mount/index.cjs"));
40
40
  var import_use_focus_return = __toESM(require("../use-focus-return/index.cjs"));
41
41
  var import_use_focus_outside = __toESM(require("../use-focus-outside/index.cjs"));
42
42
  var import_use_merge_refs = __toESM(require("../use-merge-refs/index.cjs"));
@@ -47,7 +47,7 @@ function useDialog(options) {
47
47
  currentOptions.current = options;
48
48
  }, Object.values(options));
49
49
  const constrainedTabbingRef = (0, import_use_constrained_tabbing.default)();
50
- const focusOnMountRef = (0, import_use_focus_on_mount.useFocusOnMount)(options.focusOnMount);
50
+ const focusOnMountRef = (0, import_use_focus_on_mount.default)(options.focusOnMount);
51
51
  const focusReturnRef = (0, import_use_focus_return.default)();
52
52
  const focusOutsideProps = (0, import_use_focus_outside.default)((event) => {
53
53
  if (currentOptions.current?.__unstableOnClose) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/hooks/use-dialog/index.ts"],
4
- "sourcesContent": ["/**\n * External dependencies\n */\nimport type { RefCallback, SyntheticEvent } from 'react';\n\n/**\n * WordPress dependencies\n */\nimport { useRef, useEffect, useCallback } from '@wordpress/element';\nimport { ESCAPE } from '@wordpress/keycodes';\n\n/**\n * Internal dependencies\n */\nimport useConstrainedTabbing from '../use-constrained-tabbing';\nimport { useFocusOnMount } from '../use-focus-on-mount';\nimport useFocusReturn from '../use-focus-return';\nimport useFocusOutside from '../use-focus-outside';\nimport useMergeRefs from '../use-merge-refs';\n\ntype DialogOptions = {\n\t/**\n\t * Determines focus behavior when the dialog mounts.\n\t *\n\t * - `\"firstElement\"` focuses the first tabbable element within.\n\t * - `\"firstInputElement\"` focuses the first value control within.\n\t * - `true` focuses the element itself.\n\t * - `false` does nothing and _should not be used unless an accessible\n\t * substitute behavior is implemented_.\n\t *\n\t * @default 'firstElement'\n\t */\n\tfocusOnMount?: useFocusOnMount.Mode;\n\t/**\n\t * Determines whether tabbing is constrained to within the popover,\n\t * preventing keyboard focus from leaving the popover content without\n\t * explicit focus elsewhere, or whether the popover remains part of the\n\t * wider tab order.\n\t * If no value is passed, it will be derived from `focusOnMount`.\n\t *\n\t * @see focusOnMount\n\t * @default `focusOnMount` !== false\n\t */\n\tconstrainTabbing?: boolean;\n\tonClose?: () => void;\n\t/**\n\t * Use the `onClose` prop instead.\n\t *\n\t * @deprecated\n\t */\n\t__unstableOnClose?: (\n\t\ttype: string | undefined,\n\t\tevent: SyntheticEvent\n\t) => void;\n};\n\ntype useDialogReturn = [\n\tRefCallback< HTMLElement >,\n\tReturnType< typeof useFocusOutside > & Pick< HTMLElement, 'tabIndex' >,\n];\n\n/**\n * Returns a ref and props to apply to a dialog wrapper to enable the following behaviors:\n * - constrained tabbing.\n * - focus on mount.\n * - return focus on unmount.\n * - focus outside.\n *\n * @param options Dialog Options.\n */\nfunction useDialog( options: DialogOptions ): useDialogReturn {\n\tconst currentOptions = useRef< DialogOptions >( undefined );\n\tconst { constrainTabbing = options.focusOnMount !== false } = options;\n\tuseEffect( () => {\n\t\tcurrentOptions.current = options;\n\t}, Object.values( options ) );\n\tconst constrainedTabbingRef = useConstrainedTabbing();\n\tconst focusOnMountRef = useFocusOnMount( options.focusOnMount );\n\tconst focusReturnRef = useFocusReturn();\n\tconst focusOutsideProps = useFocusOutside( ( event ) => {\n\t\t// This unstable prop is here only to manage backward compatibility\n\t\t// for the Popover component otherwise, the onClose should be enough.\n\t\tif ( currentOptions.current?.__unstableOnClose ) {\n\t\t\tcurrentOptions.current.__unstableOnClose( 'focus-outside', event );\n\t\t} else if ( currentOptions.current?.onClose ) {\n\t\t\tcurrentOptions.current.onClose();\n\t\t}\n\t} );\n\tconst closeOnEscapeRef = useCallback( ( node: HTMLElement ) => {\n\t\tif ( ! node ) {\n\t\t\treturn;\n\t\t}\n\n\t\tnode.addEventListener( 'keydown', ( event: KeyboardEvent ) => {\n\t\t\t// Close on escape.\n\t\t\tif (\n\t\t\t\tevent.keyCode === ESCAPE &&\n\t\t\t\t! event.defaultPrevented &&\n\t\t\t\tcurrentOptions.current?.onClose\n\t\t\t) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tcurrentOptions.current.onClose();\n\t\t\t}\n\t\t} );\n\t}, [] );\n\n\treturn [\n\t\tuseMergeRefs( [\n\t\t\tconstrainTabbing ? constrainedTabbingRef : null,\n\t\t\toptions.focusOnMount !== false ? focusReturnRef : null,\n\t\t\toptions.focusOnMount !== false ? focusOnMountRef : null,\n\t\t\tcloseOnEscapeRef,\n\t\t] ),\n\t\t{\n\t\t\t...focusOutsideProps,\n\t\t\ttabIndex: -1,\n\t\t},\n\t];\n}\n\nexport default useDialog;\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA,qBAA+C;AAC/C,sBAAuB;AAKvB,qCAAkC;AAClC,gCAAgC;AAChC,8BAA2B;AAC3B,+BAA4B;AAC5B,4BAAyB;AAoDzB,SAAS,UAAW,SAA0C;AAC7D,QAAM,qBAAiB,uBAAyB,MAAU;AAC1D,QAAM,EAAE,mBAAmB,QAAQ,iBAAiB,MAAM,IAAI;AAC9D,gCAAW,MAAM;AAChB,mBAAe,UAAU;AAAA,EAC1B,GAAG,OAAO,OAAQ,OAAQ,CAAE;AAC5B,QAAM,4BAAwB,+BAAAA,SAAsB;AACpD,QAAM,sBAAkB,2CAAiB,QAAQ,YAAa;AAC9D,QAAM,qBAAiB,wBAAAC,SAAe;AACtC,QAAM,wBAAoB,yBAAAC,SAAiB,CAAE,UAAW;AAGvD,QAAK,eAAe,SAAS,mBAAoB;AAChD,qBAAe,QAAQ,kBAAmB,iBAAiB,KAAM;AAAA,IAClE,WAAY,eAAe,SAAS,SAAU;AAC7C,qBAAe,QAAQ,QAAQ;AAAA,IAChC;AAAA,EACD,CAAE;AACF,QAAM,uBAAmB,4BAAa,CAAE,SAAuB;AAC9D,QAAK,CAAE,MAAO;AACb;AAAA,IACD;AAEA,SAAK,iBAAkB,WAAW,CAAE,UAA0B;AAE7D,UACC,MAAM,YAAY,0BAClB,CAAE,MAAM,oBACR,eAAe,SAAS,SACvB;AACD,cAAM,eAAe;AACrB,uBAAe,QAAQ,QAAQ;AAAA,MAChC;AAAA,IACD,CAAE;AAAA,EACH,GAAG,CAAC,CAAE;AAEN,SAAO;AAAA,QACN,sBAAAC,SAAc;AAAA,MACb,mBAAmB,wBAAwB;AAAA,MAC3C,QAAQ,iBAAiB,QAAQ,iBAAiB;AAAA,MAClD,QAAQ,iBAAiB,QAAQ,kBAAkB;AAAA,MACnD;AAAA,IACD,CAAE;AAAA,IACF;AAAA,MACC,GAAG;AAAA,MACH,UAAU;AAAA,IACX;AAAA,EACD;AACD;AAEA,IAAO,qBAAQ;",
6
- "names": ["useConstrainedTabbing", "useFocusReturn", "useFocusOutside", "useMergeRefs"]
4
+ "sourcesContent": ["/**\n * External dependencies\n */\nimport type { RefCallback, SyntheticEvent } from 'react';\n\n/**\n * WordPress dependencies\n */\nimport { useRef, useEffect, useCallback } from '@wordpress/element';\nimport { ESCAPE } from '@wordpress/keycodes';\n\n/**\n * Internal dependencies\n */\nimport useConstrainedTabbing from '../use-constrained-tabbing';\nimport useFocusOnMount from '../use-focus-on-mount';\nimport useFocusReturn from '../use-focus-return';\nimport useFocusOutside from '../use-focus-outside';\nimport useMergeRefs from '../use-merge-refs';\n\ntype DialogOptions = {\n\t/**\n\t * Determines whether focus should be automatically moved to the popover\n\t * when it mounts. `false` causes no focus shift, `true` causes the popover\n\t * itself to gain focus, and `firstElement` focuses the first focusable\n\t * element within the popover.\n\t *\n\t * @default 'firstElement'\n\t */\n\tfocusOnMount?: Parameters< typeof useFocusOnMount >[ 0 ];\n\t/**\n\t * Determines whether tabbing is constrained to within the popover,\n\t * preventing keyboard focus from leaving the popover content without\n\t * explicit focus elsewhere, or whether the popover remains part of the\n\t * wider tab order.\n\t * If no value is passed, it will be derived from `focusOnMount`.\n\t *\n\t * @see focusOnMount\n\t * @default `focusOnMount` !== false\n\t */\n\tconstrainTabbing?: boolean;\n\tonClose?: () => void;\n\t/**\n\t * Use the `onClose` prop instead.\n\t *\n\t * @deprecated\n\t */\n\t__unstableOnClose?: (\n\t\ttype: string | undefined,\n\t\tevent: SyntheticEvent\n\t) => void;\n};\n\ntype useDialogReturn = [\n\tRefCallback< HTMLElement >,\n\tReturnType< typeof useFocusOutside > & Pick< HTMLElement, 'tabIndex' >,\n];\n\n/**\n * Returns a ref and props to apply to a dialog wrapper to enable the following behaviors:\n * - constrained tabbing.\n * - focus on mount.\n * - return focus on unmount.\n * - focus outside.\n *\n * @param options Dialog Options.\n */\nfunction useDialog( options: DialogOptions ): useDialogReturn {\n\tconst currentOptions = useRef< DialogOptions >( undefined );\n\tconst { constrainTabbing = options.focusOnMount !== false } = options;\n\tuseEffect( () => {\n\t\tcurrentOptions.current = options;\n\t}, Object.values( options ) );\n\tconst constrainedTabbingRef = useConstrainedTabbing();\n\tconst focusOnMountRef = useFocusOnMount( options.focusOnMount );\n\tconst focusReturnRef = useFocusReturn();\n\tconst focusOutsideProps = useFocusOutside( ( event ) => {\n\t\t// This unstable prop is here only to manage backward compatibility\n\t\t// for the Popover component otherwise, the onClose should be enough.\n\t\tif ( currentOptions.current?.__unstableOnClose ) {\n\t\t\tcurrentOptions.current.__unstableOnClose( 'focus-outside', event );\n\t\t} else if ( currentOptions.current?.onClose ) {\n\t\t\tcurrentOptions.current.onClose();\n\t\t}\n\t} );\n\tconst closeOnEscapeRef = useCallback( ( node: HTMLElement ) => {\n\t\tif ( ! node ) {\n\t\t\treturn;\n\t\t}\n\n\t\tnode.addEventListener( 'keydown', ( event: KeyboardEvent ) => {\n\t\t\t// Close on escape.\n\t\t\tif (\n\t\t\t\tevent.keyCode === ESCAPE &&\n\t\t\t\t! event.defaultPrevented &&\n\t\t\t\tcurrentOptions.current?.onClose\n\t\t\t) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tcurrentOptions.current.onClose();\n\t\t\t}\n\t\t} );\n\t}, [] );\n\n\treturn [\n\t\tuseMergeRefs( [\n\t\t\tconstrainTabbing ? constrainedTabbingRef : null,\n\t\t\toptions.focusOnMount !== false ? focusReturnRef : null,\n\t\t\toptions.focusOnMount !== false ? focusOnMountRef : null,\n\t\t\tcloseOnEscapeRef,\n\t\t] ),\n\t\t{\n\t\t\t...focusOutsideProps,\n\t\t\ttabIndex: -1,\n\t\t},\n\t];\n}\n\nexport default useDialog;\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA,qBAA+C;AAC/C,sBAAuB;AAKvB,qCAAkC;AAClC,gCAA4B;AAC5B,8BAA2B;AAC3B,+BAA4B;AAC5B,4BAAyB;AAiDzB,SAAS,UAAW,SAA0C;AAC7D,QAAM,qBAAiB,uBAAyB,MAAU;AAC1D,QAAM,EAAE,mBAAmB,QAAQ,iBAAiB,MAAM,IAAI;AAC9D,gCAAW,MAAM;AAChB,mBAAe,UAAU;AAAA,EAC1B,GAAG,OAAO,OAAQ,OAAQ,CAAE;AAC5B,QAAM,4BAAwB,+BAAAA,SAAsB;AACpD,QAAM,sBAAkB,0BAAAC,SAAiB,QAAQ,YAAa;AAC9D,QAAM,qBAAiB,wBAAAC,SAAe;AACtC,QAAM,wBAAoB,yBAAAC,SAAiB,CAAE,UAAW;AAGvD,QAAK,eAAe,SAAS,mBAAoB;AAChD,qBAAe,QAAQ,kBAAmB,iBAAiB,KAAM;AAAA,IAClE,WAAY,eAAe,SAAS,SAAU;AAC7C,qBAAe,QAAQ,QAAQ;AAAA,IAChC;AAAA,EACD,CAAE;AACF,QAAM,uBAAmB,4BAAa,CAAE,SAAuB;AAC9D,QAAK,CAAE,MAAO;AACb;AAAA,IACD;AAEA,SAAK,iBAAkB,WAAW,CAAE,UAA0B;AAE7D,UACC,MAAM,YAAY,0BAClB,CAAE,MAAM,oBACR,eAAe,SAAS,SACvB;AACD,cAAM,eAAe;AACrB,uBAAe,QAAQ,QAAQ;AAAA,MAChC;AAAA,IACD,CAAE;AAAA,EACH,GAAG,CAAC,CAAE;AAEN,SAAO;AAAA,QACN,sBAAAC,SAAc;AAAA,MACb,mBAAmB,wBAAwB;AAAA,MAC3C,QAAQ,iBAAiB,QAAQ,iBAAiB;AAAA,MAClD,QAAQ,iBAAiB,QAAQ,kBAAkB;AAAA,MACnD;AAAA,IACD,CAAE;AAAA,IACF;AAAA,MACC,GAAG;AAAA,MACH,UAAU;AAAA,IACX;AAAA,EACD;AACD;AAEA,IAAO,qBAAQ;",
6
+ "names": ["useConstrainedTabbing", "useFocusOnMount", "useFocusReturn", "useFocusOutside", "useMergeRefs"]
7
7
  }
@@ -27,14 +27,14 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
27
  ));
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
 
30
- // packages/compose/src/hooks/use-focus-on-mount/index.ts
30
+ // packages/compose/src/hooks/use-focus-on-mount/index.js
31
31
  var use_focus_on_mount_exports = {};
32
32
  __export(use_focus_on_mount_exports, {
33
- useFocusOnMount: () => useFocusOnMount
33
+ default: () => useFocusOnMount
34
34
  });
35
35
  module.exports = __toCommonJS(use_focus_on_mount_exports);
36
- var import_dom = require("@wordpress/dom");
37
36
  var import_element = require("@wordpress/element");
37
+ var import_dom = require("@wordpress/dom");
38
38
  var import_use_ref_effect = __toESM(require("../use-ref-effect/index.cjs"));
39
39
  function useFocusOnMount(focusOnMount = "firstElement") {
40
40
  const focusOnMountRef = (0, import_element.useRef)(focusOnMount);
@@ -46,11 +46,12 @@ function useFocusOnMount(focusOnMount = "firstElement") {
46
46
  preventScroll: true
47
47
  });
48
48
  };
49
+ const timerIdRef = (0, import_element.useRef)(void 0);
49
50
  (0, import_element.useEffect)(() => {
50
51
  focusOnMountRef.current = focusOnMount;
51
52
  }, [focusOnMount]);
52
53
  return (0, import_use_ref_effect.default)((node) => {
53
- if (focusOnMountRef.current === false) {
54
+ if (!node || focusOnMountRef.current === false) {
54
55
  return;
55
56
  }
56
57
  if (node.contains(node.ownerDocument?.activeElement ?? null)) {
@@ -60,11 +61,14 @@ function useFocusOnMount(focusOnMount = "firstElement") {
60
61
  setFocus(node);
61
62
  return;
62
63
  }
63
- const timerId = setTimeout(() => {
64
+ timerIdRef.current = setTimeout(() => {
64
65
  if (focusOnMountRef.current === "firstInputElement") {
65
- const formInput = node.querySelector(
66
- 'input:not([type="hidden"]):not([disabled]), select:not([disabled]), textarea:not([disabled])'
67
- );
66
+ let formInput = null;
67
+ if (typeof window !== "undefined" && node instanceof window.Element) {
68
+ formInput = node.querySelector(
69
+ 'input:not([type="hidden"]):not([disabled]), select:not([disabled]), textarea:not([disabled])'
70
+ );
71
+ }
68
72
  if (formInput) {
69
73
  setFocus(formInput);
70
74
  return;
@@ -76,12 +80,10 @@ function useFocusOnMount(focusOnMount = "firstElement") {
76
80
  }
77
81
  }, 0);
78
82
  return () => {
79
- clearTimeout(timerId);
83
+ if (timerIdRef.current) {
84
+ clearTimeout(timerIdRef.current);
85
+ }
80
86
  };
81
87
  }, []);
82
88
  }
83
- // Annotate the CommonJS export names for ESM import in node:
84
- 0 && (module.exports = {
85
- useFocusOnMount
86
- });
87
89
  //# sourceMappingURL=index.cjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../../src/hooks/use-focus-on-mount/index.ts"],
4
- "sourcesContent": ["import { focus } from '@wordpress/dom';\nimport { useEffect, useRef } from '@wordpress/element';\nimport useRefEffect from '../use-ref-effect';\n\n/**\n * Determines focus behavior when the element mounts.\n *\n * @param focusOnMount Behavioral mode. Defaults to `\"firstElement\"` which focuses the\n * first tabbable element within; `\"firstInputElement\"` focuses the\n * first value control within; `true` focuses the element itself;\n * `false` does nothing.\n * @return Ref callback.\n *\n * @example\n * ```js\n * import { useFocusOnMount } from '@wordpress/compose';\n *\n * const WithFocusOnMount = () => {\n * const ref = useFocusOnMount()\n * return (\n * <div ref={ ref }>\n * <Button />\n * <Button />\n * </div>\n * );\n * }\n * ```\n */\nexport function useFocusOnMount(\n\tfocusOnMount: useFocusOnMount.Mode = 'firstElement'\n) {\n\tconst focusOnMountRef = useRef( focusOnMount );\n\n\t/**\n\t * Sets focus on a DOM element.\n\t *\n\t * @param target The DOM element to set focus to.\n\t */\n\tconst setFocus = ( target: HTMLElement ): void => {\n\t\ttarget.focus( {\n\t\t\t// When focusing newly mounted dialogs,\n\t\t\t// the position of the popover is often not right on the first render\n\t\t\t// This prevents the layout shifts when focusing the dialogs.\n\t\t\tpreventScroll: true,\n\t\t} );\n\t};\n\n\tuseEffect( () => {\n\t\tfocusOnMountRef.current = focusOnMount;\n\t}, [ focusOnMount ] );\n\n\treturn useRefEffect< HTMLElement >( ( node ) => {\n\t\tif ( focusOnMountRef.current === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( node.contains( node.ownerDocument?.activeElement ?? null ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (\n\t\t\tfocusOnMountRef.current !== 'firstElement' &&\n\t\t\tfocusOnMountRef.current !== 'firstInputElement'\n\t\t) {\n\t\t\tsetFocus( node );\n\t\t\treturn;\n\t\t}\n\n\t\tconst timerId = setTimeout( () => {\n\t\t\t// For 'firstInputElement' mode, try to find a form input element first\n\t\t\tif ( focusOnMountRef.current === 'firstInputElement' ) {\n\t\t\t\tconst formInput = node.querySelector< HTMLElement >(\n\t\t\t\t\t'input:not([type=\"hidden\"]):not([disabled]), select:not([disabled]), textarea:not([disabled])'\n\t\t\t\t);\n\n\t\t\t\tif ( formInput ) {\n\t\t\t\t\tsetFocus( formInput );\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Fallback to the first tabbable element\n\t\t\tconst firstTabbable = focus.tabbable.find( node )[ 0 ];\n\t\t\tif ( firstTabbable ) {\n\t\t\t\tsetFocus( firstTabbable );\n\t\t\t}\n\t\t}, 0 );\n\n\t\treturn () => {\n\t\t\tclearTimeout( timerId );\n\t\t};\n\t}, [] );\n}\n\nexport namespace useFocusOnMount {\n\texport type Mode = boolean | 'firstElement' | 'firstInputElement';\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAsB;AACtB,qBAAkC;AAClC,4BAAyB;AA0BlB,SAAS,gBACf,eAAqC,gBACpC;AACD,QAAM,sBAAkB,uBAAQ,YAAa;AAO7C,QAAM,WAAW,CAAE,WAA+B;AACjD,WAAO,MAAO;AAAA;AAAA;AAAA;AAAA,MAIb,eAAe;AAAA,IAChB,CAAE;AAAA,EACH;AAEA,gCAAW,MAAM;AAChB,oBAAgB,UAAU;AAAA,EAC3B,GAAG,CAAE,YAAa,CAAE;AAEpB,aAAO,sBAAAA,SAA6B,CAAE,SAAU;AAC/C,QAAK,gBAAgB,YAAY,OAAQ;AACxC;AAAA,IACD;AAEA,QAAK,KAAK,SAAU,KAAK,eAAe,iBAAiB,IAAK,GAAI;AACjE;AAAA,IACD;AAEA,QACC,gBAAgB,YAAY,kBAC5B,gBAAgB,YAAY,qBAC3B;AACD,eAAU,IAAK;AACf;AAAA,IACD;AAEA,UAAM,UAAU,WAAY,MAAM;AAEjC,UAAK,gBAAgB,YAAY,qBAAsB;AACtD,cAAM,YAAY,KAAK;AAAA,UACtB;AAAA,QACD;AAEA,YAAK,WAAY;AAChB,mBAAU,SAAU;AACpB;AAAA,QACD;AAAA,MACD;AAGA,YAAM,gBAAgB,iBAAM,SAAS,KAAM,IAAK,EAAG,CAAE;AACrD,UAAK,eAAgB;AACpB,iBAAU,aAAc;AAAA,MACzB;AAAA,IACD,GAAG,CAAE;AAEL,WAAO,MAAM;AACZ,mBAAc,OAAQ;AAAA,IACvB;AAAA,EACD,GAAG,CAAC,CAAE;AACP;",
3
+ "sources": ["../../../src/hooks/use-focus-on-mount/index.js"],
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useRef, useEffect } from '@wordpress/element';\nimport { focus } from '@wordpress/dom';\n\n/**\n * Internal dependencies\n */\nimport useRefEffect from '../use-ref-effect';\n\n/**\n * Hook used to focus the first tabbable element on mount.\n *\n * @param {boolean | 'firstElement' | 'firstInputElement'} focusOnMount Focus on mount mode.\n * @return {React.RefCallback<HTMLElement>} Ref callback.\n *\n * @example\n * ```js\n * import { useFocusOnMount } from '@wordpress/compose';\n *\n * const WithFocusOnMount = () => {\n * const ref = useFocusOnMount()\n * return (\n * <div ref={ ref }>\n * <Button />\n * <Button />\n * </div>\n * );\n * }\n * ```\n */\nexport default function useFocusOnMount( focusOnMount = 'firstElement' ) {\n\tconst focusOnMountRef = useRef( focusOnMount );\n\n\t/**\n\t * Sets focus on a DOM element.\n\t *\n\t * @param {HTMLElement} target The DOM element to set focus to.\n\t * @return {void}\n\t */\n\tconst setFocus = ( target ) => {\n\t\ttarget.focus( {\n\t\t\t// When focusing newly mounted dialogs,\n\t\t\t// the position of the popover is often not right on the first render\n\t\t\t// This prevents the layout shifts when focusing the dialogs.\n\t\t\tpreventScroll: true,\n\t\t} );\n\t};\n\n\t/** @type {React.MutableRefObject<ReturnType<setTimeout> | undefined>} */\n\tconst timerIdRef = useRef( undefined );\n\n\tuseEffect( () => {\n\t\tfocusOnMountRef.current = focusOnMount;\n\t}, [ focusOnMount ] );\n\n\treturn useRefEffect( ( node ) => {\n\t\tif ( ! node || focusOnMountRef.current === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( node.contains( node.ownerDocument?.activeElement ?? null ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (\n\t\t\tfocusOnMountRef.current !== 'firstElement' &&\n\t\t\tfocusOnMountRef.current !== 'firstInputElement'\n\t\t) {\n\t\t\tsetFocus( node );\n\t\t\treturn;\n\t\t}\n\n\t\ttimerIdRef.current = setTimeout( () => {\n\t\t\t// For 'firstInputElement' mode, try to find a form input element first\n\t\t\tif ( focusOnMountRef.current === 'firstInputElement' ) {\n\t\t\t\t/** @type {HTMLElement | null} */\n\t\t\t\tlet formInput = null;\n\t\t\t\tif (\n\t\t\t\t\ttypeof window !== 'undefined' &&\n\t\t\t\t\tnode instanceof window.Element\n\t\t\t\t) {\n\t\t\t\t\tformInput = node.querySelector(\n\t\t\t\t\t\t'input:not([type=\"hidden\"]):not([disabled]), select:not([disabled]), textarea:not([disabled])'\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif ( formInput ) {\n\t\t\t\t\tsetFocus( formInput );\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Fallback to the first tabbable element\n\t\t\tconst firstTabbable = focus.tabbable.find( node )[ 0 ];\n\t\t\tif ( firstTabbable ) {\n\t\t\t\tsetFocus( firstTabbable );\n\t\t\t}\n\t\t}, 0 );\n\n\t\treturn () => {\n\t\t\tif ( timerIdRef.current ) {\n\t\t\t\tclearTimeout( timerIdRef.current );\n\t\t\t}\n\t\t};\n\t}, [] );\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,qBAAkC;AAClC,iBAAsB;AAKtB,4BAAyB;AAuBV,SAAR,gBAAkC,eAAe,gBAAiB;AACxE,QAAM,sBAAkB,uBAAQ,YAAa;AAQ7C,QAAM,WAAW,CAAE,WAAY;AAC9B,WAAO,MAAO;AAAA;AAAA;AAAA;AAAA,MAIb,eAAe;AAAA,IAChB,CAAE;AAAA,EACH;AAGA,QAAM,iBAAa,uBAAQ,MAAU;AAErC,gCAAW,MAAM;AAChB,oBAAgB,UAAU;AAAA,EAC3B,GAAG,CAAE,YAAa,CAAE;AAEpB,aAAO,sBAAAA,SAAc,CAAE,SAAU;AAChC,QAAK,CAAE,QAAQ,gBAAgB,YAAY,OAAQ;AAClD;AAAA,IACD;AAEA,QAAK,KAAK,SAAU,KAAK,eAAe,iBAAiB,IAAK,GAAI;AACjE;AAAA,IACD;AAEA,QACC,gBAAgB,YAAY,kBAC5B,gBAAgB,YAAY,qBAC3B;AACD,eAAU,IAAK;AACf;AAAA,IACD;AAEA,eAAW,UAAU,WAAY,MAAM;AAEtC,UAAK,gBAAgB,YAAY,qBAAsB;AAEtD,YAAI,YAAY;AAChB,YACC,OAAO,WAAW,eAClB,gBAAgB,OAAO,SACtB;AACD,sBAAY,KAAK;AAAA,YAChB;AAAA,UACD;AAAA,QACD;AAEA,YAAK,WAAY;AAChB,mBAAU,SAAU;AACpB;AAAA,QACD;AAAA,MACD;AAGA,YAAM,gBAAgB,iBAAM,SAAS,KAAM,IAAK,EAAG,CAAE;AACrD,UAAK,eAAgB;AACpB,iBAAU,aAAc;AAAA,MACzB;AAAA,IACD,GAAG,CAAE;AAEL,WAAO,MAAM;AACZ,UAAK,WAAW,SAAU;AACzB,qBAAc,WAAW,OAAQ;AAAA,MAClC;AAAA,IACD;AAAA,EACD,GAAG,CAAC,CAAE;AACP;",
6
6
  "names": ["useRefEffect"]
7
7
  }
@@ -17,34 +17,37 @@ var __copyProps = (to, from, except, desc) => {
17
17
  };
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
 
20
- // packages/compose/src/hooks/use-media-query/index.js
20
+ // packages/compose/src/hooks/use-media-query/index.ts
21
21
  var use_media_query_exports = {};
22
22
  __export(use_media_query_exports, {
23
23
  default: () => useMediaQuery
24
24
  });
25
25
  module.exports = __toCommonJS(use_media_query_exports);
26
26
  var import_element = require("@wordpress/element");
27
- var matchMediaCache = /* @__PURE__ */ new Map();
28
- function getMediaQueryList(query) {
27
+ var perWindowCache = /* @__PURE__ */ new WeakMap();
28
+ function getMediaQueryList(view, query) {
29
29
  if (!query) {
30
30
  return null;
31
31
  }
32
+ const matchMediaCache = perWindowCache.get(view) ?? /* @__PURE__ */ new Map();
33
+ if (!perWindowCache.has(view)) {
34
+ perWindowCache.set(view, matchMediaCache);
35
+ }
32
36
  let match = matchMediaCache.get(query);
33
37
  if (match) {
34
38
  return match;
35
39
  }
36
- if (typeof window !== "undefined" && typeof window.matchMedia === "function") {
37
- match = window.matchMedia(query);
40
+ if (typeof view?.matchMedia === "function") {
41
+ match = view.matchMedia(query);
38
42
  matchMediaCache.set(query, match);
39
43
  return match;
40
44
  }
41
45
  return null;
42
46
  }
43
- function useMediaQuery(query) {
47
+ function useMediaQuery(query, view = window) {
44
48
  const source = (0, import_element.useMemo)(() => {
45
- const mediaQueryList = getMediaQueryList(query);
49
+ const mediaQueryList = getMediaQueryList(view, query);
46
50
  return {
47
- /** @type {(onStoreChange: () => void) => () => void} */
48
51
  subscribe(onStoreChange) {
49
52
  if (!mediaQueryList) {
50
53
  return () => {
@@ -62,7 +65,7 @@ function useMediaQuery(query) {
62
65
  return mediaQueryList?.matches ?? false;
63
66
  }
64
67
  };
65
- }, [query]);
68
+ }, [view, query]);
66
69
  return (0, import_element.useSyncExternalStore)(
67
70
  source.subscribe,
68
71
  source.getValue,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../../src/hooks/use-media-query/index.js"],
4
- "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useMemo, useSyncExternalStore } from '@wordpress/element';\n\nconst matchMediaCache = new Map();\n\n/**\n * A new MediaQueryList object for the media query\n *\n * @param {string} [query] Media Query.\n * @return {MediaQueryList|null} A new object for the media query\n */\nfunction getMediaQueryList( query ) {\n\tif ( ! query ) {\n\t\treturn null;\n\t}\n\n\tlet match = matchMediaCache.get( query );\n\n\tif ( match ) {\n\t\treturn match;\n\t}\n\n\tif (\n\t\ttypeof window !== 'undefined' &&\n\t\ttypeof window.matchMedia === 'function'\n\t) {\n\t\tmatch = window.matchMedia( query );\n\t\tmatchMediaCache.set( query, match );\n\t\treturn match;\n\t}\n\n\treturn null;\n}\n\n/**\n * Runs a media query and returns its value when it changes.\n *\n * @param {string} [query] Media Query.\n * @return {boolean} return value of the media query.\n */\nexport default function useMediaQuery( query ) {\n\tconst source = useMemo( () => {\n\t\tconst mediaQueryList = getMediaQueryList( query );\n\n\t\treturn {\n\t\t\t/** @type {(onStoreChange: () => void) => () => void} */\n\t\t\tsubscribe( onStoreChange ) {\n\t\t\t\tif ( ! mediaQueryList ) {\n\t\t\t\t\treturn () => {};\n\t\t\t\t}\n\n\t\t\t\t// Avoid a fatal error when browsers don't support `addEventListener` on MediaQueryList.\n\t\t\t\tmediaQueryList.addEventListener?.( 'change', onStoreChange );\n\t\t\t\treturn () => {\n\t\t\t\t\tmediaQueryList.removeEventListener?.(\n\t\t\t\t\t\t'change',\n\t\t\t\t\t\tonStoreChange\n\t\t\t\t\t);\n\t\t\t\t};\n\t\t\t},\n\t\t\tgetValue() {\n\t\t\t\treturn mediaQueryList?.matches ?? false;\n\t\t\t},\n\t\t};\n\t}, [ query ] );\n\n\treturn useSyncExternalStore(\n\t\tsource.subscribe,\n\t\tsource.getValue,\n\t\t() => false\n\t);\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,qBAA8C;AAE9C,IAAM,kBAAkB,oBAAI,IAAI;AAQhC,SAAS,kBAAmB,OAAQ;AACnC,MAAK,CAAE,OAAQ;AACd,WAAO;AAAA,EACR;AAEA,MAAI,QAAQ,gBAAgB,IAAK,KAAM;AAEvC,MAAK,OAAQ;AACZ,WAAO;AAAA,EACR;AAEA,MACC,OAAO,WAAW,eAClB,OAAO,OAAO,eAAe,YAC5B;AACD,YAAQ,OAAO,WAAY,KAAM;AACjC,oBAAgB,IAAK,OAAO,KAAM;AAClC,WAAO;AAAA,EACR;AAEA,SAAO;AACR;AAQe,SAAR,cAAgC,OAAQ;AAC9C,QAAM,aAAS,wBAAS,MAAM;AAC7B,UAAM,iBAAiB,kBAAmB,KAAM;AAEhD,WAAO;AAAA;AAAA,MAEN,UAAW,eAAgB;AAC1B,YAAK,CAAE,gBAAiB;AACvB,iBAAO,MAAM;AAAA,UAAC;AAAA,QACf;AAGA,uBAAe,mBAAoB,UAAU,aAAc;AAC3D,eAAO,MAAM;AACZ,yBAAe;AAAA,YACd;AAAA,YACA;AAAA,UACD;AAAA,QACD;AAAA,MACD;AAAA,MACA,WAAW;AACV,eAAO,gBAAgB,WAAW;AAAA,MACnC;AAAA,IACD;AAAA,EACD,GAAG,CAAE,KAAM,CAAE;AAEb,aAAO;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,EACP;AACD;",
3
+ "sources": ["../../../src/hooks/use-media-query/index.ts"],
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useMemo, useSyncExternalStore } from '@wordpress/element';\n\ntype MQLCache = Map< string, MediaQueryList >;\n\nconst perWindowCache = new WeakMap< Window, MQLCache >();\n\n/**\n * A new MediaQueryList object for the media query\n *\n * @param view Window.\n * @param [query] Media Query.\n */\nfunction getMediaQueryList(\n\tview: Window,\n\tquery?: string\n): MediaQueryList | null {\n\tif ( ! query ) {\n\t\treturn null;\n\t}\n\n\tconst matchMediaCache: MQLCache = perWindowCache.get( view ) ?? new Map();\n\n\tif ( ! perWindowCache.has( view ) ) {\n\t\tperWindowCache.set( view, matchMediaCache );\n\t}\n\n\tlet match = matchMediaCache.get( query );\n\n\tif ( match ) {\n\t\treturn match;\n\t}\n\n\tif ( typeof view?.matchMedia === 'function' ) {\n\t\tmatch = view.matchMedia( query );\n\t\tmatchMediaCache.set( query, match );\n\t\treturn match;\n\t}\n\n\treturn null;\n}\n\n/**\n * Runs a media query and returns its value when it changes.\n *\n * @param [query] Media Query.\n * @param [view] Window instance, else default to global window\n * @return return value of the media query.\n */\nexport default function useMediaQuery(\n\tquery?: string,\n\tview: Window = window\n): boolean {\n\tconst source = useMemo( () => {\n\t\tconst mediaQueryList = getMediaQueryList( view, query );\n\n\t\treturn {\n\t\t\tsubscribe( onStoreChange: any ) {\n\t\t\t\tif ( ! mediaQueryList ) {\n\t\t\t\t\treturn () => {};\n\t\t\t\t}\n\n\t\t\t\t// Avoid a fatal error when browsers don't support `addEventListener` on MediaQueryList.\n\t\t\t\tmediaQueryList.addEventListener?.( 'change', onStoreChange );\n\t\t\t\treturn () => {\n\t\t\t\t\tmediaQueryList.removeEventListener?.(\n\t\t\t\t\t\t'change',\n\t\t\t\t\t\tonStoreChange\n\t\t\t\t\t);\n\t\t\t\t};\n\t\t\t},\n\t\t\tgetValue() {\n\t\t\t\treturn mediaQueryList?.matches ?? false;\n\t\t\t},\n\t\t};\n\t}, [ view, query ] );\n\n\treturn useSyncExternalStore(\n\t\tsource.subscribe,\n\t\tsource.getValue,\n\t\t() => false\n\t);\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,qBAA8C;AAI9C,IAAM,iBAAiB,oBAAI,QAA4B;AAQvD,SAAS,kBACR,MACA,OACwB;AACxB,MAAK,CAAE,OAAQ;AACd,WAAO;AAAA,EACR;AAEA,QAAM,kBAA4B,eAAe,IAAK,IAAK,KAAK,oBAAI,IAAI;AAExE,MAAK,CAAE,eAAe,IAAK,IAAK,GAAI;AACnC,mBAAe,IAAK,MAAM,eAAgB;AAAA,EAC3C;AAEA,MAAI,QAAQ,gBAAgB,IAAK,KAAM;AAEvC,MAAK,OAAQ;AACZ,WAAO;AAAA,EACR;AAEA,MAAK,OAAO,MAAM,eAAe,YAAa;AAC7C,YAAQ,KAAK,WAAY,KAAM;AAC/B,oBAAgB,IAAK,OAAO,KAAM;AAClC,WAAO;AAAA,EACR;AAEA,SAAO;AACR;AASe,SAAR,cACN,OACA,OAAe,QACL;AACV,QAAM,aAAS,wBAAS,MAAM;AAC7B,UAAM,iBAAiB,kBAAmB,MAAM,KAAM;AAEtD,WAAO;AAAA,MACN,UAAW,eAAqB;AAC/B,YAAK,CAAE,gBAAiB;AACvB,iBAAO,MAAM;AAAA,UAAC;AAAA,QACf;AAGA,uBAAe,mBAAoB,UAAU,aAAc;AAC3D,eAAO,MAAM;AACZ,yBAAe;AAAA,YACd;AAAA,YACA;AAAA,UACD;AAAA,QACD;AAAA,MACD;AAAA,MACA,WAAW;AACV,eAAO,gBAAgB,WAAW;AAAA,MACnC;AAAA,IACD;AAAA,EACD,GAAG,CAAE,MAAM,KAAM,CAAE;AAEnB,aAAO;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,EACP;AACD;",
6
6
  "names": []
7
7
  }
@@ -58,10 +58,10 @@ var ViewportMatchWidthContext = (0, import_element.createContext)(
58
58
  null
59
59
  );
60
60
  ViewportMatchWidthContext.displayName = "ViewportMatchWidthContext";
61
- var useViewportMatch = (breakpoint, operator = ">=") => {
61
+ var useViewportMatch = (breakpoint, operator = ">=", view = window) => {
62
62
  const simulatedWidth = (0, import_element.useContext)(ViewportMatchWidthContext);
63
63
  const mediaQuery = !simulatedWidth && `(${CONDITIONS[operator]}: ${BREAKPOINTS[breakpoint]}px)`;
64
- const mediaQueryResult = (0, import_use_media_query.default)(mediaQuery || void 0);
64
+ const mediaQueryResult = (0, import_use_media_query.default)(mediaQuery || void 0, view);
65
65
  if (simulatedWidth) {
66
66
  return OPERATOR_EVALUATORS[operator](
67
67
  BREAKPOINTS[breakpoint],
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/hooks/use-viewport-match/index.js"],
4
- "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { createContext, useContext } from '@wordpress/element';\n\n/**\n * Internal dependencies\n */\nimport useMediaQuery from '../use-media-query';\n\n/**\n * @typedef {\"xhuge\" | \"huge\" | \"wide\" | \"xlarge\" | \"large\" | \"medium\" | \"small\" | \"mobile\"} WPBreakpoint\n */\n\n/**\n * Hash of breakpoint names with pixel width at which it becomes effective.\n *\n * @see _breakpoints.scss\n *\n * @type {Record<WPBreakpoint, number>}\n */\nconst BREAKPOINTS = {\n\txhuge: 1920,\n\thuge: 1440,\n\twide: 1280,\n\txlarge: 1080,\n\tlarge: 960,\n\tmedium: 782,\n\tsmall: 600,\n\tmobile: 480,\n};\n\n/**\n * @typedef {\">=\" | \"<\"} WPViewportOperator\n */\n\n/**\n * Object mapping media query operators to the condition to be used.\n *\n * @type {Record<WPViewportOperator, string>}\n */\nconst CONDITIONS = {\n\t'>=': 'min-width',\n\t'<': 'max-width',\n};\n\n/**\n * Object mapping media query operators to a function that given a breakpointValue and a width evaluates if the operator matches the values.\n *\n * @type {Record<WPViewportOperator, (breakpointValue: number, width: number) => boolean>}\n */\nconst OPERATOR_EVALUATORS = {\n\t'>=': ( breakpointValue, width ) => width >= breakpointValue,\n\t'<': ( breakpointValue, width ) => width < breakpointValue,\n};\n\nconst ViewportMatchWidthContext = createContext(\n\t/** @type {null | number} */ ( null )\n);\nViewportMatchWidthContext.displayName = 'ViewportMatchWidthContext';\n\n/**\n * Returns true if the viewport matches the given query, or false otherwise.\n *\n * @param {WPBreakpoint} breakpoint Breakpoint size name.\n * @param {WPViewportOperator} [operator=\">=\"] Viewport operator.\n *\n * @example\n *\n * ```js\n * useViewportMatch( 'huge', '<' );\n * useViewportMatch( 'medium' );\n * ```\n *\n * @return {boolean} Whether viewport matches query.\n */\nconst useViewportMatch = ( breakpoint, operator = '>=' ) => {\n\tconst simulatedWidth = useContext( ViewportMatchWidthContext );\n\tconst mediaQuery =\n\t\t! simulatedWidth &&\n\t\t`(${ CONDITIONS[ operator ] }: ${ BREAKPOINTS[ breakpoint ] }px)`;\n\tconst mediaQueryResult = useMediaQuery( mediaQuery || undefined );\n\tif ( simulatedWidth ) {\n\t\treturn OPERATOR_EVALUATORS[ operator ](\n\t\t\tBREAKPOINTS[ breakpoint ],\n\t\t\tsimulatedWidth\n\t\t);\n\t}\n\treturn mediaQueryResult;\n};\n\nuseViewportMatch.__experimentalWidthProvider =\n\tViewportMatchWidthContext.Provider;\n\nexport default useViewportMatch;\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,qBAA0C;AAK1C,6BAA0B;AAa1B,IAAM,cAAc;AAAA,EACnB,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AACT;AAWA,IAAM,aAAa;AAAA,EAClB,MAAM;AAAA,EACN,KAAK;AACN;AAOA,IAAM,sBAAsB;AAAA,EAC3B,MAAM,CAAE,iBAAiB,UAAW,SAAS;AAAA,EAC7C,KAAK,CAAE,iBAAiB,UAAW,QAAQ;AAC5C;AAEA,IAAM,gCAA4B;AAAA;AAAA,EACF;AAChC;AACA,0BAA0B,cAAc;AAiBxC,IAAM,mBAAmB,CAAE,YAAY,WAAW,SAAU;AAC3D,QAAM,qBAAiB,2BAAY,yBAA0B;AAC7D,QAAM,aACL,CAAE,kBACF,IAAK,WAAY,QAAS,CAAE,KAAM,YAAa,UAAW,CAAE;AAC7D,QAAM,uBAAmB,uBAAAA,SAAe,cAAc,MAAU;AAChE,MAAK,gBAAiB;AACrB,WAAO,oBAAqB,QAAS;AAAA,MACpC,YAAa,UAAW;AAAA,MACxB;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;AAEA,iBAAiB,8BAChB,0BAA0B;AAE3B,IAAO,6BAAQ;",
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { createContext, useContext } from '@wordpress/element';\n\n/**\n * Internal dependencies\n */\nimport useMediaQuery from '../use-media-query';\n\n/**\n * @typedef {\"xhuge\" | \"huge\" | \"wide\" | \"xlarge\" | \"large\" | \"medium\" | \"small\" | \"mobile\"} WPBreakpoint\n */\n\n/**\n * Hash of breakpoint names with pixel width at which it becomes effective.\n *\n * @see _breakpoints.scss\n *\n * @type {Record<WPBreakpoint, number>}\n */\nconst BREAKPOINTS = {\n\txhuge: 1920,\n\thuge: 1440,\n\twide: 1280,\n\txlarge: 1080,\n\tlarge: 960,\n\tmedium: 782,\n\tsmall: 600,\n\tmobile: 480,\n};\n\n/**\n * @typedef {\">=\" | \"<\"} WPViewportOperator\n */\n\n/**\n * Object mapping media query operators to the condition to be used.\n *\n * @type {Record<WPViewportOperator, string>}\n */\nconst CONDITIONS = {\n\t'>=': 'min-width',\n\t'<': 'max-width',\n};\n\n/**\n * Object mapping media query operators to a function that given a breakpointValue and a width evaluates if the operator matches the values.\n *\n * @type {Record<WPViewportOperator, (breakpointValue: number, width: number) => boolean>}\n */\nconst OPERATOR_EVALUATORS = {\n\t'>=': ( breakpointValue, width ) => width >= breakpointValue,\n\t'<': ( breakpointValue, width ) => width < breakpointValue,\n};\n\nconst ViewportMatchWidthContext = createContext(\n\t/** @type {null | number} */ ( null )\n);\nViewportMatchWidthContext.displayName = 'ViewportMatchWidthContext';\n\n/**\n * Returns true if the viewport matches the given query, or false otherwise.\n *\n * @param {WPBreakpoint} breakpoint Breakpoint size name.\n * @param {WPViewportOperator} [operator=\">=\"] Viewport operator.\n * @param {Window} [view=window] Window instance in which to perform viewport matching.\n *\n * @example\n *\n * ```js\n * useViewportMatch( 'huge', '<' );\n * useViewportMatch( 'medium' );\n * ```\n *\n * @return {boolean} Whether viewport matches query.\n */\nconst useViewportMatch = ( breakpoint, operator = '>=', view = window ) => {\n\tconst simulatedWidth = useContext( ViewportMatchWidthContext );\n\tconst mediaQuery =\n\t\t! simulatedWidth &&\n\t\t`(${ CONDITIONS[ operator ] }: ${ BREAKPOINTS[ breakpoint ] }px)`;\n\tconst mediaQueryResult = useMediaQuery( mediaQuery || undefined, view );\n\tif ( simulatedWidth ) {\n\t\treturn OPERATOR_EVALUATORS[ operator ](\n\t\t\tBREAKPOINTS[ breakpoint ],\n\t\t\tsimulatedWidth\n\t\t);\n\t}\n\treturn mediaQueryResult;\n};\n\nuseViewportMatch.__experimentalWidthProvider =\n\tViewportMatchWidthContext.Provider;\n\nexport default useViewportMatch;\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,qBAA0C;AAK1C,6BAA0B;AAa1B,IAAM,cAAc;AAAA,EACnB,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AACT;AAWA,IAAM,aAAa;AAAA,EAClB,MAAM;AAAA,EACN,KAAK;AACN;AAOA,IAAM,sBAAsB;AAAA,EAC3B,MAAM,CAAE,iBAAiB,UAAW,SAAS;AAAA,EAC7C,KAAK,CAAE,iBAAiB,UAAW,QAAQ;AAC5C;AAEA,IAAM,gCAA4B;AAAA;AAAA,EACF;AAChC;AACA,0BAA0B,cAAc;AAkBxC,IAAM,mBAAmB,CAAE,YAAY,WAAW,MAAM,OAAO,WAAY;AAC1E,QAAM,qBAAiB,2BAAY,yBAA0B;AAC7D,QAAM,aACL,CAAE,kBACF,IAAK,WAAY,QAAS,CAAE,KAAM,YAAa,UAAW,CAAE;AAC7D,QAAM,uBAAmB,uBAAAA,SAAe,cAAc,QAAW,IAAK;AACtE,MAAK,gBAAiB;AACrB,WAAO,oBAAqB,QAAS;AAAA,MACpC,YAAa,UAAW;AAAA,MACxB;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;AAEA,iBAAiB,8BAChB,0BAA0B;AAE3B,IAAO,6BAAQ;",
6
6
  "names": ["useMediaQuery"]
7
7
  }