react-aria 3.51.0 → 3.52.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 (135) hide show
  1. package/dist/exports/index.cjs +1 -0
  2. package/dist/exports/index.cjs.map +1 -1
  3. package/dist/exports/index.js +2 -2
  4. package/dist/exports/index.js.map +1 -1
  5. package/dist/exports/index.mjs +2 -2
  6. package/dist/exports/index.mjs.map +1 -1
  7. package/dist/exports/private/utils/domHelpers.cjs +1 -0
  8. package/dist/exports/private/utils/domHelpers.cjs.map +1 -1
  9. package/dist/exports/private/utils/domHelpers.js +2 -2
  10. package/dist/exports/private/utils/domHelpers.js.map +1 -1
  11. package/dist/exports/private/utils/domHelpers.mjs +2 -2
  12. package/dist/exports/private/utils/domHelpers.mjs.map +1 -1
  13. package/dist/exports/useFocusVisible.cjs +1 -0
  14. package/dist/exports/useFocusVisible.cjs.map +1 -1
  15. package/dist/exports/useFocusVisible.js +2 -2
  16. package/dist/exports/useFocusVisible.js.map +1 -1
  17. package/dist/exports/useFocusVisible.mjs +2 -2
  18. package/dist/exports/useFocusVisible.mjs.map +1 -1
  19. package/dist/private/actiongroup/useActionGroup.cjs +3 -1
  20. package/dist/private/actiongroup/useActionGroup.cjs.map +1 -1
  21. package/dist/private/actiongroup/useActionGroup.js +3 -1
  22. package/dist/private/actiongroup/useActionGroup.js.map +1 -1
  23. package/dist/private/actiongroup/useActionGroup.mjs +3 -1
  24. package/dist/private/actiongroup/useActionGroup.mjs.map +1 -1
  25. package/dist/private/calendar/useRangeCalendar.cjs +1 -1
  26. package/dist/private/calendar/useRangeCalendar.cjs.map +1 -1
  27. package/dist/private/calendar/useRangeCalendar.js +2 -2
  28. package/dist/private/calendar/useRangeCalendar.js.map +1 -1
  29. package/dist/private/calendar/useRangeCalendar.mjs +2 -2
  30. package/dist/private/calendar/useRangeCalendar.mjs.map +1 -1
  31. package/dist/private/color/useColorField.cjs +26 -4
  32. package/dist/private/color/useColorField.cjs.map +1 -1
  33. package/dist/private/color/useColorField.js +26 -4
  34. package/dist/private/color/useColorField.js.map +1 -1
  35. package/dist/private/color/useColorField.mjs +26 -4
  36. package/dist/private/color/useColorField.mjs.map +1 -1
  37. package/dist/private/combobox/useComboBox.cjs +1 -1
  38. package/dist/private/combobox/useComboBox.cjs.map +1 -1
  39. package/dist/private/combobox/useComboBox.js +1 -1
  40. package/dist/private/combobox/useComboBox.js.map +1 -1
  41. package/dist/private/combobox/useComboBox.mjs +1 -1
  42. package/dist/private/combobox/useComboBox.mjs.map +1 -1
  43. package/dist/private/focus/FocusScope.cjs +7 -2
  44. package/dist/private/focus/FocusScope.cjs.map +1 -1
  45. package/dist/private/focus/FocusScope.js +7 -2
  46. package/dist/private/focus/FocusScope.js.map +1 -1
  47. package/dist/private/focus/FocusScope.mjs +7 -2
  48. package/dist/private/focus/FocusScope.mjs.map +1 -1
  49. package/dist/private/interactions/useFocusVisible.cjs +15 -3
  50. package/dist/private/interactions/useFocusVisible.cjs.map +1 -1
  51. package/dist/private/interactions/useFocusVisible.js +15 -3
  52. package/dist/private/interactions/useFocusVisible.js.map +1 -1
  53. package/dist/private/interactions/useFocusVisible.mjs +15 -3
  54. package/dist/private/interactions/useFocusVisible.mjs.map +1 -1
  55. package/dist/private/interactions/utils.cjs +23 -13
  56. package/dist/private/interactions/utils.cjs.map +1 -1
  57. package/dist/private/interactions/utils.js +25 -15
  58. package/dist/private/interactions/utils.js.map +1 -1
  59. package/dist/private/interactions/utils.mjs +25 -15
  60. package/dist/private/interactions/utils.mjs.map +1 -1
  61. package/dist/private/overlays/calculatePosition.cjs +3 -2
  62. package/dist/private/overlays/calculatePosition.cjs.map +1 -1
  63. package/dist/private/overlays/calculatePosition.js +5 -2
  64. package/dist/private/overlays/calculatePosition.js.map +1 -1
  65. package/dist/private/overlays/calculatePosition.mjs +3 -2
  66. package/dist/private/overlays/calculatePosition.mjs.map +1 -1
  67. package/dist/private/overlays/useOverlayPosition.cjs +5 -0
  68. package/dist/private/overlays/useOverlayPosition.cjs.map +1 -1
  69. package/dist/private/overlays/useOverlayPosition.js +6 -1
  70. package/dist/private/overlays/useOverlayPosition.js.map +1 -1
  71. package/dist/private/overlays/useOverlayPosition.mjs +6 -1
  72. package/dist/private/overlays/useOverlayPosition.mjs.map +1 -1
  73. package/dist/private/overlays/usePreventScroll.cjs +27 -35
  74. package/dist/private/overlays/usePreventScroll.cjs.map +1 -1
  75. package/dist/private/overlays/usePreventScroll.js +27 -35
  76. package/dist/private/overlays/usePreventScroll.js.map +1 -1
  77. package/dist/private/overlays/usePreventScroll.mjs +27 -35
  78. package/dist/private/overlays/usePreventScroll.mjs.map +1 -1
  79. package/dist/private/selection/useSelectableCollection.cjs +1 -0
  80. package/dist/private/selection/useSelectableCollection.cjs.map +1 -1
  81. package/dist/private/selection/useSelectableCollection.js +1 -0
  82. package/dist/private/selection/useSelectableCollection.js.map +1 -1
  83. package/dist/private/selection/useSelectableCollection.mjs +1 -0
  84. package/dist/private/selection/useSelectableCollection.mjs.map +1 -1
  85. package/dist/private/tabs/TabsKeyboardDelegate.cjs +3 -1
  86. package/dist/private/tabs/TabsKeyboardDelegate.cjs.map +1 -1
  87. package/dist/private/tabs/TabsKeyboardDelegate.js +3 -1
  88. package/dist/private/tabs/TabsKeyboardDelegate.js.map +1 -1
  89. package/dist/private/tabs/TabsKeyboardDelegate.mjs +3 -1
  90. package/dist/private/tabs/TabsKeyboardDelegate.mjs.map +1 -1
  91. package/dist/private/tokenfield/useToken.cjs +19 -4
  92. package/dist/private/tokenfield/useToken.cjs.map +1 -1
  93. package/dist/private/tokenfield/useToken.js +20 -4
  94. package/dist/private/tokenfield/useToken.js.map +1 -1
  95. package/dist/private/tokenfield/useToken.mjs +19 -4
  96. package/dist/private/tokenfield/useToken.mjs.map +1 -1
  97. package/dist/private/tokenfield/useTokenField.cjs +118 -42
  98. package/dist/private/tokenfield/useTokenField.cjs.map +1 -1
  99. package/dist/private/tokenfield/useTokenField.js +121 -44
  100. package/dist/private/tokenfield/useTokenField.js.map +1 -1
  101. package/dist/private/tokenfield/useTokenField.mjs +119 -43
  102. package/dist/private/tokenfield/useTokenField.mjs.map +1 -1
  103. package/dist/private/utils/domHelpers.cjs +21 -0
  104. package/dist/private/utils/domHelpers.cjs.map +1 -1
  105. package/dist/private/utils/domHelpers.js +20 -1
  106. package/dist/private/utils/domHelpers.js.map +1 -1
  107. package/dist/private/utils/domHelpers.mjs +20 -1
  108. package/dist/private/utils/domHelpers.mjs.map +1 -1
  109. package/dist/private/utils/getMetaValue.cjs +36 -0
  110. package/dist/private/utils/getMetaValue.cjs.map +1 -0
  111. package/dist/private/utils/getMetaValue.js +31 -0
  112. package/dist/private/utils/getMetaValue.js.map +1 -0
  113. package/dist/private/utils/getMetaValue.mjs +31 -0
  114. package/dist/private/utils/getMetaValue.mjs.map +1 -0
  115. package/dist/private/utils/getNonce.cjs +6 -10
  116. package/dist/private/utils/getNonce.cjs.map +1 -1
  117. package/dist/private/utils/getNonce.js +7 -11
  118. package/dist/private/utils/getNonce.js.map +1 -1
  119. package/dist/private/utils/getNonce.mjs +7 -11
  120. package/dist/private/utils/getNonce.mjs.map +1 -1
  121. package/dist/private/utils/useEvent.cjs +7 -9
  122. package/dist/private/utils/useEvent.cjs.map +1 -1
  123. package/dist/private/utils/useEvent.js +7 -9
  124. package/dist/private/utils/useEvent.js.map +1 -1
  125. package/dist/private/utils/useEvent.mjs +7 -9
  126. package/dist/private/utils/useEvent.mjs.map +1 -1
  127. package/dist/types/exports/index.d.ts +2 -2
  128. package/dist/types/exports/private/utils/domHelpers.d.ts +1 -1
  129. package/dist/types/exports/useFocusVisible.d.ts +2 -1
  130. package/dist/types/src/tokenfield/useTokenField.d.ts +3 -2
  131. package/dist/types/src/utils/domHelpers.d.ts +6 -2
  132. package/dist/types/src/utils/getMetaValue.d.ts +7 -0
  133. package/dist/types/src/utils/useEvent.d.ts +2 -2
  134. package/dist/types/src/virtualizer/Virtualizer.d.ts +3 -3
  135. package/package.json +6 -5
@@ -1,3 +1,4 @@
1
+ import {isVirtualClick as $fa0ef9dfcca012a7$export$60278871457622de} from "../utils/isVirtualEvent.js";
1
2
  import {useEvent as $c3cab330536504ec$export$90fc3a17d93f704c} from "../utils/useEvent.js";
2
3
  import {useState as $bIBdX$useState, useRef as $bIBdX$useRef} from "react";
3
4
 
@@ -13,14 +14,15 @@ import {useState as $bIBdX$useState, useRef as $bIBdX$useRef} from "react";
13
14
  * governing
14
15
  */
15
16
 
17
+
16
18
  function $a06747c3f56c51df$export$31dcd79391e423fe(// Unused but matches the normal signature.
17
19
  _props, _state, ref) {
18
20
  let [isSelected, setSelected] = (0, $bIBdX$useState)(false);
19
21
  (0, $c3cab330536504ec$export$90fc3a17d93f704c)((0, $bIBdX$useRef)(typeof document !== 'undefined' ? document : null), 'selectionchange', ()=>{
20
22
  let selection = window.getSelection();
21
- if (!selection || selection.rangeCount === 0 || !ref.current) return;
22
- let range = selection.getRangeAt(0);
23
- if (!range.collapsed && range.intersectsNode(ref.current)) setSelected(true);
23
+ if (!selection || !ref.current) return;
24
+ let range = selection.rangeCount === 0 ? null : selection.getRangeAt(0);
25
+ if (!(range === null || range === void 0 ? void 0 : range.collapsed) && (range === null || range === void 0 ? void 0 : range.intersectsNode(ref.current))) setSelected(true);
24
26
  else setSelected(false);
25
27
  });
26
28
  return {
@@ -29,7 +31,21 @@ _props, _state, ref) {
29
31
  suppressContentEditableWarning: true,
30
32
  style: {
31
33
  userSelect: 'all',
32
- WebkitUserSelect: 'all'
34
+ WebkitUserSelect: 'all',
35
+ WebkitTapHighlightColor: 'transparent'
36
+ },
37
+ onClick (e) {
38
+ var _ref_current;
39
+ // Select the token when a screen reader clicks on it.
40
+ if (isSelected || !(0, $fa0ef9dfcca012a7$export$60278871457622de)(e.nativeEvent)) return;
41
+ let selection = window.getSelection();
42
+ let wrapper = (_ref_current = ref.current) === null || _ref_current === void 0 ? void 0 : _ref_current.parentElement;
43
+ if (!selection || !wrapper) return;
44
+ let range = document.createRange();
45
+ range.setStartBefore(wrapper);
46
+ range.setEndAfter(wrapper);
47
+ selection.removeAllRanges();
48
+ selection.addRange(range);
33
49
  }
34
50
  },
35
51
  isSelected: isSelected
@@ -1 +1 @@
1
- {"mappings":";;;AAAA;;;;;;;;;;CAUC;;AAkBM,SAAS,0CACd,2CAA2C;AAC3C,MAAkB,EAClB,MAAW,EACX,GAAsC;IAEtC,IAAI,CAAC,YAAY,YAAY,GAAG,CAAA,GAAA,eAAO,EAAE;IAEzC,CAAA,GAAA,yCAAO,EAAE,CAAA,GAAA,aAAK,EAAE,OAAO,aAAa,cAAc,WAAW,OAAO,mBAAmB;QACrF,IAAI,YAAY,OAAO,YAAY;QACnC,IAAI,CAAC,aAAa,UAAU,UAAU,KAAK,KAAK,CAAC,IAAI,OAAO,EAC1D;QAGF,IAAI,QAAQ,UAAU,UAAU,CAAC;QACjC,IAAI,CAAC,MAAM,SAAS,IAAI,MAAM,cAAc,CAAC,IAAI,OAAO,GACtD,YAAY;aAEZ,YAAY;IAEhB;IAEA,OAAO;QACL,YAAY;YACV,iBAAiB;YACjB,gCAAgC;YAChC,OAAO;gBACL,YAAY;gBACZ,kBAAkB;YACpB;QACF;oBACA;IACF;AACF","sources":["packages/react-aria/src/tokenfield/useToken.ts"],"sourcesContent":["/*\n * Copyright 2026 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing\n */\n\nimport {HTMLAttributes, RefObject, useRef, useState} from 'react';\nimport {useEvent} from '../utils/useEvent';\n\nexport interface TokenProps {}\n\nexport interface TokenAria {\n /** Props for the token element. */\n tokenProps: HTMLAttributes<HTMLSpanElement>;\n /** Whether the token is currently selected. */\n isSelected: boolean;\n}\n\n/**\n * Provides the behavior and accessibility implementation for a token within a token field.\n * A token field allows users to enter text with inline tokens.\n */\nexport function useToken(\n // Unused but matches the normal signature.\n _props: TokenProps,\n _state: any,\n ref: RefObject<HTMLSpanElement | null>\n): TokenAria {\n let [isSelected, setSelected] = useState(false);\n\n useEvent(useRef(typeof document !== 'undefined' ? document : null), 'selectionchange', () => {\n let selection = window.getSelection();\n if (!selection || selection.rangeCount === 0 || !ref.current) {\n return;\n }\n\n let range = selection.getRangeAt(0);\n if (!range.collapsed && range.intersectsNode(ref.current)) {\n setSelected(true);\n } else {\n setSelected(false);\n }\n });\n\n return {\n tokenProps: {\n contentEditable: false,\n suppressContentEditableWarning: true,\n style: {\n userSelect: 'all',\n WebkitUserSelect: 'all'\n }\n },\n isSelected\n };\n}\n"],"names":[],"version":3,"file":"useToken.js.map"}
1
+ {"mappings":";;;;AAAA;;;;;;;;;;CAUC;;;AAmBM,SAAS,0CACd,2CAA2C;AAC3C,MAAkB,EAClB,MAAW,EACX,GAAsC;IAEtC,IAAI,CAAC,YAAY,YAAY,GAAG,CAAA,GAAA,eAAO,EAAE;IAEzC,CAAA,GAAA,yCAAO,EAAE,CAAA,GAAA,aAAK,EAAE,OAAO,aAAa,cAAc,WAAW,OAAO,mBAAmB;QACrF,IAAI,YAAY,OAAO,YAAY;QACnC,IAAI,CAAC,aAAa,CAAC,IAAI,OAAO,EAC5B;QAGF,IAAI,QAAQ,UAAU,UAAU,KAAK,IAAI,OAAO,UAAU,UAAU,CAAC;QACrE,IAAI,EAAC,kBAAA,4BAAA,MAAO,SAAS,MAAI,kBAAA,4BAAA,MAAO,cAAc,CAAC,IAAI,OAAO,IACxD,YAAY;aAEZ,YAAY;IAEhB;IAEA,OAAO;QACL,YAAY;YACV,iBAAiB;YACjB,gCAAgC;YAChC,OAAO;gBACL,YAAY;gBACZ,kBAAkB;gBAClB,yBAAyB;YAC3B;YACA,SAAQ,CAAC;oBAMO;gBALd,sDAAsD;gBACtD,IAAI,cAAc,CAAC,CAAA,GAAA,yCAAa,EAAE,EAAE,WAAW,GAC7C;gBAEF,IAAI,YAAY,OAAO,YAAY;gBACnC,IAAI,WAAU,eAAA,IAAI,OAAO,cAAX,mCAAA,aAAa,aAAa;gBACxC,IAAI,CAAC,aAAa,CAAC,SACjB;gBAEF,IAAI,QAAQ,SAAS,WAAW;gBAChC,MAAM,cAAc,CAAC;gBACrB,MAAM,WAAW,CAAC;gBAClB,UAAU,eAAe;gBACzB,UAAU,QAAQ,CAAC;YACrB;QACF;oBACA;IACF;AACF","sources":["packages/react-aria/src/tokenfield/useToken.ts"],"sourcesContent":["/*\n * Copyright 2026 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing\n */\n\nimport {HTMLAttributes, RefObject, useRef, useState} from 'react';\nimport {isVirtualClick} from '../utils/isVirtualEvent';\nimport {useEvent} from '../utils/useEvent';\n\nexport interface TokenProps {}\n\nexport interface TokenAria {\n /** Props for the token element. */\n tokenProps: HTMLAttributes<HTMLSpanElement>;\n /** Whether the token is currently selected. */\n isSelected: boolean;\n}\n\n/**\n * Provides the behavior and accessibility implementation for a token within a token field.\n * A token field allows users to enter text with inline tokens.\n */\nexport function useToken(\n // Unused but matches the normal signature.\n _props: TokenProps,\n _state: any,\n ref: RefObject<HTMLSpanElement | null>\n): TokenAria {\n let [isSelected, setSelected] = useState(false);\n\n useEvent(useRef(typeof document !== 'undefined' ? document : null), 'selectionchange', () => {\n let selection = window.getSelection();\n if (!selection || !ref.current) {\n return;\n }\n\n let range = selection.rangeCount === 0 ? null : selection.getRangeAt(0);\n if (!range?.collapsed && range?.intersectsNode(ref.current)) {\n setSelected(true);\n } else {\n setSelected(false);\n }\n });\n\n return {\n tokenProps: {\n contentEditable: false,\n suppressContentEditableWarning: true,\n style: {\n userSelect: 'all',\n WebkitUserSelect: 'all',\n WebkitTapHighlightColor: 'transparent'\n },\n onClick(e) {\n // Select the token when a screen reader clicks on it.\n if (isSelected || !isVirtualClick(e.nativeEvent)) {\n return;\n }\n let selection = window.getSelection();\n let wrapper = ref.current?.parentElement;\n if (!selection || !wrapper) {\n return;\n }\n let range = document.createRange();\n range.setStartBefore(wrapper);\n range.setEndAfter(wrapper);\n selection.removeAllRanges();\n selection.addRange(range);\n }\n },\n isSelected\n };\n}\n"],"names":[],"version":3,"file":"useToken.js.map"}
@@ -1,3 +1,4 @@
1
+ import {isVirtualClick as $b5c62b033c25b96d$export$60278871457622de} from "../utils/isVirtualEvent.mjs";
1
2
  import {useEvent as $600b3cf69ae46262$export$90fc3a17d93f704c} from "../utils/useEvent.mjs";
2
3
  import {useState as $gQiz1$useState, useRef as $gQiz1$useRef} from "react";
3
4
 
@@ -13,14 +14,15 @@ import {useState as $gQiz1$useState, useRef as $gQiz1$useRef} from "react";
13
14
  * governing
14
15
  */
15
16
 
17
+
16
18
  function $d089f4b2a715a8e0$export$31dcd79391e423fe(// Unused but matches the normal signature.
17
19
  _props, _state, ref) {
18
20
  let [isSelected, setSelected] = (0, $gQiz1$useState)(false);
19
21
  (0, $600b3cf69ae46262$export$90fc3a17d93f704c)((0, $gQiz1$useRef)(typeof document !== 'undefined' ? document : null), 'selectionchange', ()=>{
20
22
  let selection = window.getSelection();
21
- if (!selection || selection.rangeCount === 0 || !ref.current) return;
22
- let range = selection.getRangeAt(0);
23
- if (!range.collapsed && range.intersectsNode(ref.current)) setSelected(true);
23
+ if (!selection || !ref.current) return;
24
+ let range = selection.rangeCount === 0 ? null : selection.getRangeAt(0);
25
+ if (!range?.collapsed && range?.intersectsNode(ref.current)) setSelected(true);
24
26
  else setSelected(false);
25
27
  });
26
28
  return {
@@ -29,7 +31,20 @@ _props, _state, ref) {
29
31
  suppressContentEditableWarning: true,
30
32
  style: {
31
33
  userSelect: 'all',
32
- WebkitUserSelect: 'all'
34
+ WebkitUserSelect: 'all',
35
+ WebkitTapHighlightColor: 'transparent'
36
+ },
37
+ onClick (e) {
38
+ // Select the token when a screen reader clicks on it.
39
+ if (isSelected || !(0, $b5c62b033c25b96d$export$60278871457622de)(e.nativeEvent)) return;
40
+ let selection = window.getSelection();
41
+ let wrapper = ref.current?.parentElement;
42
+ if (!selection || !wrapper) return;
43
+ let range = document.createRange();
44
+ range.setStartBefore(wrapper);
45
+ range.setEndAfter(wrapper);
46
+ selection.removeAllRanges();
47
+ selection.addRange(range);
33
48
  }
34
49
  },
35
50
  isSelected: isSelected
@@ -1 +1 @@
1
- {"mappings":";;;AAAA;;;;;;;;;;CAUC;;AAkBM,SAAS,0CACd,2CAA2C;AAC3C,MAAkB,EAClB,MAAW,EACX,GAAsC;IAEtC,IAAI,CAAC,YAAY,YAAY,GAAG,CAAA,GAAA,eAAO,EAAE;IAEzC,CAAA,GAAA,yCAAO,EAAE,CAAA,GAAA,aAAK,EAAE,OAAO,aAAa,cAAc,WAAW,OAAO,mBAAmB;QACrF,IAAI,YAAY,OAAO,YAAY;QACnC,IAAI,CAAC,aAAa,UAAU,UAAU,KAAK,KAAK,CAAC,IAAI,OAAO,EAC1D;QAGF,IAAI,QAAQ,UAAU,UAAU,CAAC;QACjC,IAAI,CAAC,MAAM,SAAS,IAAI,MAAM,cAAc,CAAC,IAAI,OAAO,GACtD,YAAY;aAEZ,YAAY;IAEhB;IAEA,OAAO;QACL,YAAY;YACV,iBAAiB;YACjB,gCAAgC;YAChC,OAAO;gBACL,YAAY;gBACZ,kBAAkB;YACpB;QACF;oBACA;IACF;AACF","sources":["packages/react-aria/src/tokenfield/useToken.ts"],"sourcesContent":["/*\n * Copyright 2026 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing\n */\n\nimport {HTMLAttributes, RefObject, useRef, useState} from 'react';\nimport {useEvent} from '../utils/useEvent';\n\nexport interface TokenProps {}\n\nexport interface TokenAria {\n /** Props for the token element. */\n tokenProps: HTMLAttributes<HTMLSpanElement>;\n /** Whether the token is currently selected. */\n isSelected: boolean;\n}\n\n/**\n * Provides the behavior and accessibility implementation for a token within a token field.\n * A token field allows users to enter text with inline tokens.\n */\nexport function useToken(\n // Unused but matches the normal signature.\n _props: TokenProps,\n _state: any,\n ref: RefObject<HTMLSpanElement | null>\n): TokenAria {\n let [isSelected, setSelected] = useState(false);\n\n useEvent(useRef(typeof document !== 'undefined' ? document : null), 'selectionchange', () => {\n let selection = window.getSelection();\n if (!selection || selection.rangeCount === 0 || !ref.current) {\n return;\n }\n\n let range = selection.getRangeAt(0);\n if (!range.collapsed && range.intersectsNode(ref.current)) {\n setSelected(true);\n } else {\n setSelected(false);\n }\n });\n\n return {\n tokenProps: {\n contentEditable: false,\n suppressContentEditableWarning: true,\n style: {\n userSelect: 'all',\n WebkitUserSelect: 'all'\n }\n },\n isSelected\n };\n}\n"],"names":[],"version":3,"file":"useToken.mjs.map"}
1
+ {"mappings":";;;;AAAA;;;;;;;;;;CAUC;;;AAmBM,SAAS,0CACd,2CAA2C;AAC3C,MAAkB,EAClB,MAAW,EACX,GAAsC;IAEtC,IAAI,CAAC,YAAY,YAAY,GAAG,CAAA,GAAA,eAAO,EAAE;IAEzC,CAAA,GAAA,yCAAO,EAAE,CAAA,GAAA,aAAK,EAAE,OAAO,aAAa,cAAc,WAAW,OAAO,mBAAmB;QACrF,IAAI,YAAY,OAAO,YAAY;QACnC,IAAI,CAAC,aAAa,CAAC,IAAI,OAAO,EAC5B;QAGF,IAAI,QAAQ,UAAU,UAAU,KAAK,IAAI,OAAO,UAAU,UAAU,CAAC;QACrE,IAAI,CAAC,OAAO,aAAa,OAAO,eAAe,IAAI,OAAO,GACxD,YAAY;aAEZ,YAAY;IAEhB;IAEA,OAAO;QACL,YAAY;YACV,iBAAiB;YACjB,gCAAgC;YAChC,OAAO;gBACL,YAAY;gBACZ,kBAAkB;gBAClB,yBAAyB;YAC3B;YACA,SAAQ,CAAC;gBACP,sDAAsD;gBACtD,IAAI,cAAc,CAAC,CAAA,GAAA,yCAAa,EAAE,EAAE,WAAW,GAC7C;gBAEF,IAAI,YAAY,OAAO,YAAY;gBACnC,IAAI,UAAU,IAAI,OAAO,EAAE;gBAC3B,IAAI,CAAC,aAAa,CAAC,SACjB;gBAEF,IAAI,QAAQ,SAAS,WAAW;gBAChC,MAAM,cAAc,CAAC;gBACrB,MAAM,WAAW,CAAC;gBAClB,UAAU,eAAe;gBACzB,UAAU,QAAQ,CAAC;YACrB;QACF;oBACA;IACF;AACF","sources":["packages/react-aria/src/tokenfield/useToken.ts"],"sourcesContent":["/*\n * Copyright 2026 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing\n */\n\nimport {HTMLAttributes, RefObject, useRef, useState} from 'react';\nimport {isVirtualClick} from '../utils/isVirtualEvent';\nimport {useEvent} from '../utils/useEvent';\n\nexport interface TokenProps {}\n\nexport interface TokenAria {\n /** Props for the token element. */\n tokenProps: HTMLAttributes<HTMLSpanElement>;\n /** Whether the token is currently selected. */\n isSelected: boolean;\n}\n\n/**\n * Provides the behavior and accessibility implementation for a token within a token field.\n * A token field allows users to enter text with inline tokens.\n */\nexport function useToken(\n // Unused but matches the normal signature.\n _props: TokenProps,\n _state: any,\n ref: RefObject<HTMLSpanElement | null>\n): TokenAria {\n let [isSelected, setSelected] = useState(false);\n\n useEvent(useRef(typeof document !== 'undefined' ? document : null), 'selectionchange', () => {\n let selection = window.getSelection();\n if (!selection || !ref.current) {\n return;\n }\n\n let range = selection.rangeCount === 0 ? null : selection.getRangeAt(0);\n if (!range?.collapsed && range?.intersectsNode(ref.current)) {\n setSelected(true);\n } else {\n setSelected(false);\n }\n });\n\n return {\n tokenProps: {\n contentEditable: false,\n suppressContentEditableWarning: true,\n style: {\n userSelect: 'all',\n WebkitUserSelect: 'all',\n WebkitTapHighlightColor: 'transparent'\n },\n onClick(e) {\n // Select the token when a screen reader clicks on it.\n if (isSelected || !isVirtualClick(e.nativeEvent)) {\n return;\n }\n let selection = window.getSelection();\n let wrapper = ref.current?.parentElement;\n if (!selection || !wrapper) {\n return;\n }\n let range = document.createRange();\n range.setStartBefore(wrapper);\n range.setEndAfter(wrapper);\n selection.removeAllRanges();\n selection.addRange(range);\n }\n },\n isSelected\n };\n}\n"],"names":[],"version":3,"file":"useToken.mjs.map"}
@@ -19,8 +19,8 @@ function $parcel$export(e, n, v, s) {
19
19
  }
20
20
 
21
21
  $parcel$export(module.exports, "useTokenField", function () { return $a3a7b013e6c801ed$export$adf3c8de3c7afc8b; });
22
- $parcel$export(module.exports, "getSelection", function () { return $a3a7b013e6c801ed$export$ca798a7e6e94638c; });
23
22
  $parcel$export(module.exports, "setTokenFieldSelection", function () { return $a3a7b013e6c801ed$export$9cafaa09e78b6e4b; });
23
+ $parcel$export(module.exports, "getSelection", function () { return $a3a7b013e6c801ed$export$ca798a7e6e94638c; });
24
24
  $parcel$export(module.exports, "tokenFieldPositionToDOMRange", function () { return $a3a7b013e6c801ed$export$30729a8cd0694a7c; });
25
25
  /*
26
26
  * Copyright 2026 Adobe. All rights reserved.
@@ -111,21 +111,27 @@ function $a3a7b013e6c801ed$export$adf3c8de3c7afc8b(props, state, ref) {
111
111
  if (state.isComposing && value !== nextValue.current) stopComposition();
112
112
  nextValue.current = value;
113
113
  });
114
- let caretPosition = (0, $bmmaU$react.useRef)(null);
114
+ let selectedRange = (0, $bmmaU$react.useRef)(null);
115
115
  (0, $429333cab433657c$exports.useLayoutEffect)(()=>{
116
- if (ref.current && value.caretPosition && !state.isComposing && value.caretPosition !== caretPosition.current) {
116
+ if (ref.current && !state.isComposing && value.selectedRange !== selectedRange.current) {
117
117
  // Only move the caret when the field is already focused.
118
- if (ref.current === (0, $da02ee888921bc9e$exports.getActiveElement)((0, $49582955cc364b1c$exports.getOwnerDocument)(ref.current))) $a3a7b013e6c801ed$var$setCursor(ref.current, value.caretPosition);
119
- caretPosition.current = value.caretPosition;
118
+ if (ref.current === (0, $da02ee888921bc9e$exports.getActiveElement)((0, $49582955cc364b1c$exports.getOwnerDocument)(ref.current))) {
119
+ $a3a7b013e6c801ed$export$9cafaa09e78b6e4b(ref.current, value.selectedRange);
120
+ $a3a7b013e6c801ed$var$announceToken(value);
121
+ }
122
+ selectedRange.current = value.selectedRange;
120
123
  }
121
124
  });
122
125
  // Handle text editing commands and prevent browser default behavior.
123
126
  (0, $6e76e65001bbcda2$exports.useEvent)(ref, 'beforeinput', (e)=>{
124
127
  // Android sometimes doesn't fire a compositionend event before a regular input event.
125
128
  if (state.isComposing && !e.isComposing) stopComposition();
126
- let selection = window.getSelection();
127
- if (!selection || selection.rangeCount === 0) return;
128
- let range = selection.getRangeAt(0);
129
+ let range = e.getTargetRanges()[0];
130
+ if (!range) {
131
+ let selection = window.getSelection();
132
+ if (!selection || selection.rangeCount === 0) return;
133
+ range = selection.getRangeAt(0);
134
+ }
129
135
  let [start, end] = $a3a7b013e6c801ed$var$rangeToPositions(ref.current, range);
130
136
  // https://www.w3.org/TR/input-events-2/#interface-InputEvent-Attributes
131
137
  switch(e.inputType){
@@ -179,7 +185,7 @@ function $a3a7b013e6c801ed$export$adf3c8de3c7afc8b(props, state, ref) {
179
185
  case 'deleteContent':
180
186
  case 'deleteByCut':
181
187
  case 'deleteCompositionText':
182
- if (!range.collapsed) {
188
+ if (!range.collapsed && !$a3a7b013e6c801ed$var$isSamePosition(start, end)) {
183
189
  apply((tokens)=>tokens.replaceRange(start, end, ''));
184
190
  break;
185
191
  }
@@ -251,15 +257,19 @@ function $a3a7b013e6c801ed$export$adf3c8de3c7afc8b(props, state, ref) {
251
257
  value.endCoalescing();
252
258
  // When the cursor moves next to a token, announce it.
253
259
  // Otherwise the screen reader will only announce the first/last character.
254
- if (window.getSelection()?.isCollapsed) {
255
- let [start, end] = $a3a7b013e6c801ed$export$ca798a7e6e94638c(ref.current);
256
- if (start.offset === 0) {
257
- let segment = value.segments[start.index];
258
- if (segment?.type !== 'token') segment = value.segments[start.index - 1];
259
- if (segment?.type === 'token') (0, $74b2c5b1e7ea9589$exports.announce)(segment.text, 'assertive');
260
- // Update the caret position in the value.
261
- state.setValue((value)=>value.withCaretPosition(end));
262
- }
260
+ let range = $a3a7b013e6c801ed$export$6ec3e5953919831d(ref.current);
261
+ if (!range) return;
262
+ $a3a7b013e6c801ed$var$announceToken(value, range);
263
+ // Update the selected range in the value.
264
+ state.setValue((value)=>value.withSelectedRange(range));
265
+ });
266
+ // Clear selection on blur.
267
+ (0, $6e76e65001bbcda2$exports.useEvent)(ref, 'blur', (e)=>{
268
+ if (!e.isTrusted) return;
269
+ let selection = window.getSelection();
270
+ if (ref.current && selection && selection.containsNode(ref.current, true)) {
271
+ selection.removeAllRanges();
272
+ state.setValue((value)=>value.withSelectedRange(new (0, $bmmaU$reactstatelyuseTokenFieldState.TokenFieldValue).SelectedRange(value.caretPosition)));
263
273
  }
264
274
  });
265
275
  // Override the default triple click behavior to ensure that tokens get selected.
@@ -272,7 +282,7 @@ function $a3a7b013e6c801ed$export$adf3c8de3c7afc8b(props, state, ref) {
272
282
  let end = value.findLineBoundary(selection[1], (0, $bmmaU$reactstatelyuseTokenFieldState.TokenFieldValue).Direction.Forward);
273
283
  if (start && end) {
274
284
  e.preventDefault();
275
- $a3a7b013e6c801ed$export$9cafaa09e78b6e4b(ref.current, start, end, true);
285
+ $a3a7b013e6c801ed$export$9cafaa09e78b6e4b(ref.current, new (0, $bmmaU$reactstatelyuseTokenFieldState.TokenFieldValue).SelectedRange(start, end), true);
276
286
  }
277
287
  }
278
288
  });
@@ -425,15 +435,22 @@ function $a3a7b013e6c801ed$export$ca798a7e6e94638c(container) {
425
435
  let range = selection.getRangeAt(0);
426
436
  return $a3a7b013e6c801ed$var$rangeToPositions(container, range);
427
437
  }
438
+ function $a3a7b013e6c801ed$export$6ec3e5953919831d(container) {
439
+ let selection = window.getSelection();
440
+ if (!selection || !selection.anchorNode || !selection.focusNode || !(0, $da02ee888921bc9e$exports.nodeContains)(container, selection.anchorNode) || !(0, $da02ee888921bc9e$exports.nodeContains)(container, selection.focusNode)) return null;
441
+ let anchor = $a3a7b013e6c801ed$var$getPosition(container, selection.anchorNode, selection.anchorOffset, false);
442
+ let current = $a3a7b013e6c801ed$var$getPosition(container, selection.focusNode, selection.focusOffset, !selection.isCollapsed);
443
+ return new (0, $bmmaU$reactstatelyuseTokenFieldState.TokenFieldValue).SelectedRange(anchor, current);
444
+ }
428
445
  function $a3a7b013e6c801ed$var$rangeToPositions(container, range) {
429
- let start = $a3a7b013e6c801ed$var$getPosition(container, range.startContainer, range.startOffset);
430
- let end = $a3a7b013e6c801ed$var$getPosition(container, range.endContainer, range.endOffset);
446
+ let start = $a3a7b013e6c801ed$var$getPosition(container, range.startContainer, range.startOffset, false);
447
+ let end = $a3a7b013e6c801ed$var$getPosition(container, range.endContainer, range.endOffset, !range.collapsed);
431
448
  return [
432
449
  start,
433
450
  end
434
451
  ];
435
452
  }
436
- function $a3a7b013e6c801ed$var$getPosition(container, node, offset) {
453
+ function $a3a7b013e6c801ed$var$getPosition(container, node, offset, isRangeEnd = false) {
437
454
  if (node === container) return {
438
455
  index: offset,
439
456
  offset: 0
@@ -446,7 +463,7 @@ function $a3a7b013e6c801ed$var$getPosition(container, node, offset) {
446
463
  let atEnd;
447
464
  let endOffset = 0;
448
465
  if (originalNode === tokenNode) // Cursor is inside the token.
449
- atEnd = offset > 0;
466
+ atEnd = isRangeEnd || offset > 0;
450
467
  else if (originalNode === node) // Cursor is inside the wrapper element.
451
468
  atEnd = offset > 1;
452
469
  else {
@@ -474,37 +491,81 @@ function $a3a7b013e6c801ed$var$getPosition(container, node, offset) {
474
491
  }
475
492
  let $a3a7b013e6c801ed$var$isProgrammaticSelectionChange = Symbol('isProgrammaticSelectionChange');
476
493
  function $a3a7b013e6c801ed$var$setCursor(root, pos, fireEvent = false) {
477
- $a3a7b013e6c801ed$export$9cafaa09e78b6e4b(root, pos, pos, fireEvent);
494
+ $a3a7b013e6c801ed$export$9cafaa09e78b6e4b(root, new (0, $bmmaU$reactstatelyuseTokenFieldState.TokenFieldValue).SelectedRange(pos), fireEvent);
478
495
  }
479
- function $a3a7b013e6c801ed$export$9cafaa09e78b6e4b(root, start, end, fireEvent = false) {
496
+ function $a3a7b013e6c801ed$export$9cafaa09e78b6e4b(root, selectedRange, fireEvent = false) {
480
497
  let selection = window.getSelection();
481
498
  if (selection) {
482
- let range = $a3a7b013e6c801ed$var$createDOMRange(root, start, end);
499
+ // Use setBaseAndExtent to preserve the selection direction. A plain Range +
500
+ // addRange always produces a forward selection and collapses when the
501
+ // anchor comes after the current position (backward selections).
502
+ let [anchorNode, anchorOffset] = $a3a7b013e6c801ed$var$getDOMPosition(root, selectedRange.anchor);
503
+ let [focusNode, focusOffset] = $a3a7b013e6c801ed$var$getDOMPosition(root, selectedRange.current);
483
504
  root[$a3a7b013e6c801ed$var$isProgrammaticSelectionChange] = !fireEvent;
484
- selection.removeAllRanges();
485
- selection.addRange(range);
505
+ // Only set selection if it has changed, because this can clobber the browser's selection direction.
506
+ if (selection.anchorNode !== anchorNode || selection.anchorOffset !== anchorOffset || selection.focusNode !== focusNode || selection.focusOffset !== focusOffset) selection.setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset);
486
507
  }
487
508
  }
488
509
  function $a3a7b013e6c801ed$export$30729a8cd0694a7c(root, pos) {
489
- return $a3a7b013e6c801ed$var$createDOMRange(root, pos, pos);
510
+ // Unlike createDOMRange (used for caret/selection placement), this range is only
511
+ // measured via getBoundingClientRect to position things like an autocomplete popover.
512
+ // Place the endpoints inside the token's zero width space wrappers so the range has a
513
+ // valid rect at the token, rather than a collapsed root-level position.
514
+ let range = document.createRange();
515
+ let [startContainer, startOffset] = $a3a7b013e6c801ed$var$getDOMRectPosition(root, pos);
516
+ range.setStart(startContainer, startOffset);
517
+ range.setEnd(startContainer, startOffset);
518
+ return range;
519
+ }
520
+ function $a3a7b013e6c801ed$var$getDOMRectPosition(root, pos) {
521
+ let child = root.childNodes[pos.index];
522
+ if (child && child.nodeType === Node.ELEMENT_NODE) {
523
+ // Place the position inside the zero width space wrappers around the token.
524
+ if (pos.offset > 0) return [
525
+ child.lastChild,
526
+ 1
527
+ ];
528
+ else return [
529
+ child.firstChild,
530
+ 0
531
+ ];
532
+ }
533
+ return $a3a7b013e6c801ed$var$getDOMPosition(root, pos);
490
534
  }
491
535
  function $a3a7b013e6c801ed$var$createDOMRange(root, start, end) {
492
536
  let range = document.createRange();
493
- let startChild = root.childNodes[start.index];
494
- if (!startChild) range.setStart(root, Math.min(root.childNodes.length, start.index));
495
- else if (startChild.nodeType === Node.ELEMENT_NODE) {
496
- // Place the cursor outside the token wrapper element.
497
- if (start.offset > 0) range.setStartAfter(startChild);
498
- else range.setStartBefore(startChild);
499
- } else range.setStart(startChild, start.offset);
500
- let endChild = root.childNodes[end.index];
501
- if (!endChild) range.setEnd(root, Math.min(root.childNodes.length, end.index));
502
- else if (endChild.nodeType === Node.ELEMENT_NODE) {
503
- if (end.offset > 0) range.setEndAfter(endChild);
504
- else range.setEndBefore(endChild);
505
- } else range.setEnd(endChild, end.offset);
537
+ let [startContainer, startOffset] = $a3a7b013e6c801ed$var$getDOMPosition(root, start);
538
+ let [endContainer, endOffset] = $a3a7b013e6c801ed$var$getDOMPosition(root, end);
539
+ range.setStart(startContainer, startOffset);
540
+ range.setEnd(endContainer, endOffset);
506
541
  return range;
507
542
  }
543
+ function $a3a7b013e6c801ed$var$getDOMPosition(root, pos) {
544
+ let index = Math.max(0, Math.min(root.childNodes.length, pos.index));
545
+ let child = root.childNodes[index];
546
+ if (!child) return [
547
+ root,
548
+ index
549
+ ];
550
+ else if (child.nodeType === Node.ELEMENT_NODE) {
551
+ // Place the cursor outside the token wrapper element.
552
+ // This is necessary for composition events.
553
+ if (pos.offset > 0) return [
554
+ root,
555
+ index + 1
556
+ ];
557
+ else return [
558
+ root,
559
+ index
560
+ ];
561
+ } else {
562
+ let offset = Math.max(0, Math.min(child.textContent?.length ?? 0, pos.offset));
563
+ return [
564
+ child,
565
+ offset
566
+ ];
567
+ }
568
+ }
508
569
  function $a3a7b013e6c801ed$var$isSamePosition(a, b) {
509
570
  return a.index === b.index && a.offset === b.offset;
510
571
  }
@@ -582,6 +643,21 @@ function $a3a7b013e6c801ed$var$trackMutations(element) {
582
643
  }
583
644
  };
584
645
  }
646
+ function $a3a7b013e6c801ed$var$announceToken(value, range = value.selectedRange) {
647
+ if (range.isCollapsed) {
648
+ // Announce adjacent tokens.
649
+ let segment = value.segments[range.current.index];
650
+ if (segment && segment.type !== 'token') {
651
+ if (range.current.offset === 0) segment = value.segments[range.current.index - 1];
652
+ else if (range.current.offset === segment.text.length) segment = value.segments[range.current.index + 1];
653
+ }
654
+ if (segment?.type === 'token') (0, $74b2c5b1e7ea9589$exports.announce)(segment.text, 'assertive');
655
+ } else {
656
+ // Announce token if it is the only thing selected.
657
+ let selected = value.slice(range.start, range.end).segments;
658
+ if (selected.length === 1 && selected[0].type === 'token') (0, $74b2c5b1e7ea9589$exports.announce)(selected[0].text, 'assertive');
659
+ }
660
+ }
585
661
 
586
662
 
587
663
  //# sourceMappingURL=useTokenField.cjs.map
@@ -1 +1 @@
1
- {"mappings":"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","sources":["packages/react-aria/src/tokenfield/useTokenField.ts"],"sourcesContent":["/*\n * Copyright 2026 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing\n */\n\nimport {announce} from '../live-announcer/LiveAnnouncer';\nimport {AriaLabelingProps, DOMAttributes, FocusableProps} from '@react-types/shared';\nimport {\n ClipboardEventHandler,\n HTMLAttributes,\n RefObject,\n useCallback,\n useMemo,\n useRef\n} from 'react';\nimport {getActiveElement} from '../utils/shadowdom/DOMFunctions';\nimport {getOwnerDocument} from '../utils/domHelpers';\nimport {isMac} from '../utils/platform';\nimport {mergeProps} from '../utils/mergeProps';\nimport {\n Position,\n TokenFieldProps,\n TokenFieldSegment,\n TokenFieldState,\n TokenFieldValue\n} from 'react-stately/useTokenFieldState';\nimport {setInteractionModality} from '../interactions/useFocusVisible';\nimport {useEvent} from '../utils/useEvent';\nimport {useField} from '../label/useField';\nimport {useFocusable} from '../interactions/useFocusable';\nimport {useKeyboard} from '../interactions/useKeyboard';\nimport {useLayoutEffect} from '../utils/useLayoutEffect';\nimport {useLocale} from '../i18n/I18nProvider';\n\nexport interface AriaTokenFieldProps<T extends TokenFieldValue = TokenFieldValue>\n extends TokenFieldProps<T>, FocusableProps, AriaLabelingProps {\n /**\n * The accessibility role of the token field.\n *\n * @default 'textbox'\n */\n role?: 'textbox' | 'searchbox' | 'combobox';\n /** Whether the token field allows newlines. */\n allowsNewlines?: boolean;\n /** Whether the token field is read only. */\n isReadOnly?: boolean;\n /** Whether the token field is disabled. */\n isDisabled?: boolean;\n /** A function that is called when the user presses the Enter key. */\n onSubmit?: () => void;\n /** Handler that is called when a key is pressed. */\n onKeyDown?: (e: React.KeyboardEvent<HTMLDivElement>) => void;\n /** Handler that is called when a key is released. */\n onKeyUp?: (e: React.KeyboardEvent<HTMLDivElement>) => void;\n /**\n * Handler that is called when the user copies text. See\n * [MDN](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/oncopy).\n */\n onCopy?: ClipboardEventHandler<T>;\n\n /**\n * Handler that is called when the user cuts text. See\n * [MDN](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/oncut).\n */\n onCut?: ClipboardEventHandler<T>;\n\n /**\n * Handler that is called when the user pastes text. See\n * [MDN](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/onpaste).\n */\n onPaste?: ClipboardEventHandler<T>;\n}\n\nexport interface TokenFieldAria {\n /** Props for the token field's input element. */\n tokenFieldProps: HTMLAttributes<HTMLDivElement>;\n /** Props for the text field's visible label element, if any. */\n labelProps: DOMAttributes;\n /** Props for the text field's description element, if any. */\n descriptionProps: DOMAttributes;\n}\n\nconst CLIPBOARD_MIME_TYPE = 'application/vnd.react-aria.tokens+json';\n\n/**\n * Provides the behavior and accessibility implementation for a token field.\n * A token field allows users to enter text with inline tokens.\n *\n * @param props - Props for the token field.\n * @param state - State for the token field, as returned by `useTokenFieldState`.\n */\nexport function useTokenField<T extends TokenFieldValue = TokenFieldValue>(\n props: AriaTokenFieldProps<T>,\n state: TokenFieldState,\n ref: RefObject<HTMLDivElement | null>\n): TokenFieldAria {\n let {\n role = 'textbox',\n allowsNewlines: multiline = false,\n isReadOnly = false,\n isDisabled = false,\n 'aria-details': ariaDetails\n } = props;\n\n let {value} = state;\n let {locale} = useLocale();\n let graphemeSegmenter = useMemo(\n () => new Intl.Segmenter(locale, {granularity: 'grapheme'}),\n [locale]\n );\n let wordSegmenter = useMemo(() => new Intl.Segmenter(locale, {granularity: 'word'}), [locale]);\n\n let dropPosition = useRef<Position | null>(null);\n let transferredData = useRef<TokenFieldSegment[] | null>(null);\n\n let nextValue = useRef<TokenFieldValue | null>(null);\n let apply = (fn: (value: TokenFieldValue) => TokenFieldValue) => {\n state.setValue(value => {\n let newValue = fn(value);\n nextValue.current = newValue;\n return newValue;\n });\n };\n\n // Composition events are not cancelable. The browser will mutate the DOM, making it out of sync with React.\n // To account for this, we prevent React from re-rendering during composition, and track DOM mutations performed\n // by the browser. When composition ends, we revert the DOM to its original state, and re-render with React.\n // Mutating the DOM in any way during composition breaks the IME, causing composition to end unexpectedly.\n // During composition, we still emit updates via onChange to ensure that things like autocomplete work,\n // but we don't actually re-render to the DOM unless the value changes from what we expect (e.g. inserting a completion).\n let mutationTracker = useMutationTracker(ref);\n let startComposition = useCallback(() => {\n mutationTracker.start();\n state.setComposing(true);\n }, [state, mutationTracker]);\n let stopComposition = useCallback(() => {\n mutationTracker.stop();\n state.setComposing(false);\n }, [state, mutationTracker]);\n\n useEvent(ref, 'compositionstart', () => {\n startComposition();\n\n let range = window.getSelection()?.getRangeAt(0);\n if (range) {\n let [start, end] = rangeToPositions(ref.current!, range);\n\n // Normalize the range to ensure it is not inside a token, otherwise the browser\n // will attempt to insert the composed text into the token instead of replacing it.\n let r = createDOMRange(ref.current!, start, end);\n if (r.startContainer !== range.startContainer || r.startOffset !== range.startOffset) {\n range.setStart(r.startContainer, r.startOffset);\n }\n if (r.endContainer !== range.endContainer || r.endOffset !== range.endOffset) {\n range.setEnd(r.endContainer, r.endOffset);\n }\n }\n });\n\n useEvent(ref, 'compositionend', stopComposition);\n\n // If a prop update occurs during composition that doesn't match the expected value,\n // end composition and re-render the controlled value.\n useLayoutEffect(() => {\n if (state.isComposing && value !== nextValue.current) {\n stopComposition();\n }\n nextValue.current = value;\n });\n\n let caretPosition = useRef<Position | null>(null);\n useLayoutEffect(() => {\n if (\n ref.current &&\n value.caretPosition &&\n !state.isComposing &&\n value.caretPosition !== caretPosition.current\n ) {\n // Only move the caret when the field is already focused.\n if (ref.current === getActiveElement(getOwnerDocument(ref.current))) {\n setCursor(ref.current, value.caretPosition);\n }\n caretPosition.current = value.caretPosition;\n }\n });\n\n // Handle text editing commands and prevent browser default behavior.\n useEvent(ref, 'beforeinput', e => {\n // Android sometimes doesn't fire a compositionend event before a regular input event.\n if (state.isComposing && !e.isComposing) {\n stopComposition();\n }\n\n let selection = window.getSelection();\n if (!selection || selection.rangeCount === 0) {\n return;\n }\n let range = selection.getRangeAt(0);\n let [start, end] = rangeToPositions(ref.current!, range);\n\n // https://www.w3.org/TR/input-events-2/#interface-InputEvent-Attributes\n switch (e.inputType) {\n case 'insertText':\n case 'insertReplacementText':\n case 'insertCompositionText':\n case 'insertFromComposition': // Removed from the spec, but still fired by Safari.\n case 'insertFromPaste':\n case 'insertFromYank':\n case 'insertFromDrop': {\n let data: TokenFieldSegment[] = [{type: 'text', text: e.data ?? ''}];\n if (transferredData.current) {\n data = transferredData.current;\n transferredData.current = null;\n } else if (e.dataTransfer) {\n let parsed = e.dataTransfer.types.includes(CLIPBOARD_MIME_TYPE)\n ? parseSegments(e.dataTransfer.getData(CLIPBOARD_MIME_TYPE))\n : null;\n if (parsed) {\n data = parsed;\n } else if (e.dataTransfer.types.includes('text/plain')) {\n data[0].text = e.dataTransfer.getData('text/plain');\n }\n }\n\n if (e.inputType === 'insertFromDrop' && dropPosition.current) {\n start = end = dropPosition.current;\n dropPosition.current = null;\n }\n\n if (!multiline) {\n for (let segment of data) {\n segment.text = segment.text.replace(/[\\r\\n]+/g, ' ');\n }\n }\n\n apply(tokens =>\n tokens.replaceRangeWithSegments(\n start,\n end,\n data,\n // Don't coalesce paste/drop events with other edits.\n e.inputType === 'insertText' ||\n e.inputType === 'insertCompositionText' ||\n e.inputType === 'insertFromComposition'\n )\n );\n break;\n }\n case 'insertParagraph': {\n if (props.onSubmit) {\n props.onSubmit();\n break;\n }\n // fallthrough\n }\n case 'insertLineBreak': {\n if (multiline) {\n apply(tokens => tokens.replaceRange(start, end, '\\n'));\n }\n break;\n }\n case 'deleteContentBackward':\n case 'deleteContentForward':\n case 'deleteWordBackward':\n case 'deleteWordForward':\n case 'deleteHardLineForward':\n case 'deleteHardLineBackward':\n case 'deleteSoftLineForward':\n case 'deleteSoftLineBackward':\n case 'deleteContent':\n case 'deleteByCut':\n case 'deleteCompositionText': {\n if (!range.collapsed) {\n apply(tokens => tokens.replaceRange(start, end, ''));\n break;\n }\n\n switch (e.inputType) {\n case 'deleteContentBackward': {\n apply(tokens =>\n tokens.delete(start, graphemeSegmenter, TokenFieldValue.Direction.Backward)\n );\n break;\n }\n case 'deleteContentForward':\n apply(tokens =>\n tokens.delete(start, graphemeSegmenter, TokenFieldValue.Direction.Forward)\n );\n break;\n case 'deleteWordBackward': {\n apply(tokens =>\n tokens.delete(start, wordSegmenter, TokenFieldValue.Direction.Backward)\n );\n break;\n }\n case 'deleteWordForward':\n apply(tokens => tokens.delete(start, wordSegmenter, TokenFieldValue.Direction.Forward));\n break;\n case 'deleteHardLineForward':\n case 'deleteSoftLineForward': // TODO: this usually deletes to the nearest *visual* line break rather than a hard break\n apply(tokens => tokens.deleteLine(start, TokenFieldValue.Direction.Forward));\n break;\n case 'deleteHardLineBackward':\n case 'deleteSoftLineBackward':\n apply(tokens => tokens.deleteLine(start, TokenFieldValue.Direction.Backward));\n break;\n }\n break;\n }\n case 'deleteByDrag': {\n apply(tokens => {\n let endOffset =\n start.index === end.index ? end.offset : tokens.segments[start.index].text.length;\n let change = tokens.replaceRange(start, end, '');\n if (\n dropPosition.current &&\n dropPosition.current.index === start.index &&\n dropPosition.current.offset >= start.offset\n ) {\n dropPosition.current.offset -= endOffset - start.offset;\n }\n\n return change;\n });\n break;\n }\n }\n\n e.preventDefault();\n });\n\n let writeClipboardData = (e: ClipboardEvent | DragEvent) => {\n if ('clipboardData' in e) {\n e.preventDefault();\n }\n let selection = getSelection(ref.current!);\n if (!selection) {\n return;\n }\n let [start, end] = selection;\n let slice = value.slice(start, end);\n let dataTransfer = 'clipboardData' in e ? e.clipboardData : e.dataTransfer;\n dataTransfer?.setData(CLIPBOARD_MIME_TYPE, JSON.stringify(slice.segments));\n dataTransfer?.setData('text/plain', slice.toString());\n\n if (e.type === 'cut') {\n apply(tokens => tokens.replaceRange(start, end, '', false));\n }\n };\n\n useEvent(ref, 'copy', writeClipboardData);\n useEvent(ref, 'cut', writeClipboardData);\n useEvent(ref, 'dragstart', writeClipboardData);\n useEvent(ref, 'paste', e => {\n // Safari doesn't pass the custom clipboard data type to beforeinput dataTransfer so we handle it here.\n if (e.clipboardData && e.clipboardData.types.includes(CLIPBOARD_MIME_TYPE)) {\n transferredData.current = parseSegments(e.clipboardData.getData(CLIPBOARD_MIME_TYPE));\n }\n });\n\n // Store the cursor position on drop so we know where to insert when the insertFromDrop event occurs.\n useEvent(ref, 'drop', e => {\n if (typeof document.caretPositionFromPoint === 'function') {\n let pos = document.caretPositionFromPoint(e.clientX, e.clientY);\n if (pos) {\n dropPosition.current = getPosition(ref.current!, pos.offsetNode, pos.offset);\n }\n } else if (typeof document.caretRangeFromPoint === 'function') {\n let range = document.caretRangeFromPoint(e.clientX, e.clientY);\n if (range) {\n dropPosition.current = getPosition(ref.current!, range.startContainer, range.startOffset);\n }\n }\n\n if (e.dataTransfer && e.dataTransfer.types.includes(CLIPBOARD_MIME_TYPE)) {\n transferredData.current = parseSegments(e.dataTransfer.getData(CLIPBOARD_MIME_TYPE));\n }\n });\n\n useSelectionChange(ref, () => {\n if (state.isComposing) {\n return;\n }\n\n value.endCoalescing();\n\n // When the cursor moves next to a token, announce it.\n // Otherwise the screen reader will only announce the first/last character.\n if (window.getSelection()?.isCollapsed) {\n let [start, end] = getSelection(ref.current!)!;\n if (start.offset === 0) {\n let segment = value.segments[start.index];\n if (segment?.type !== 'token') {\n segment = value.segments[start.index - 1];\n }\n if (segment?.type === 'token') {\n announce(segment.text, 'assertive');\n }\n\n // Update the caret position in the value.\n state.setValue(value => value.withCaretPosition(end));\n }\n }\n });\n\n // Override the default triple click behavior to ensure that tokens get selected.\n // Some browsers only select the text between tokens instead of the entire line.\n useEvent(ref, 'mousedown', e => {\n if (e.detail === 3) {\n let selection = getSelection(ref.current!);\n if (!selection) {\n return;\n }\n\n let start = value.findLineBoundary(selection[0], TokenFieldValue.Direction.Backward);\n let end = value.findLineBoundary(selection[1], TokenFieldValue.Direction.Forward);\n if (start && end) {\n e.preventDefault();\n setTokenFieldSelection(ref.current!, start, end, true);\n }\n }\n });\n\n let moveSelection = (\n direction: 'left' | 'right',\n granularity: 'character' | 'word',\n extend = false\n ) => {\n let selection = window.getSelection();\n if (!selection || selection.rangeCount === 0 || !selection.focusNode || !selection.anchorNode) {\n return false;\n }\n\n // Pressing an arrow with a non-empty selection collapses it to the corresponding edge.\n // The browser handles this natively.\n if (!extend && !selection.isCollapsed) {\n return false;\n }\n\n // Move the caret using the browser's native caret movement (Selection.modify) so that\n // bidirectional text is handled correctly. Repeat until the position actually changes\n // to account for the zero width spaces around tokens.\n let pos = getPosition(ref.current!, selection.focusNode, selection.focusOffset);\n while (true) {\n let {focusNode, focusOffset} = selection;\n selection.modify(extend ? 'extend' : 'move', direction, granularity);\n if (selection.focusNode === focusNode && selection.focusOffset === focusOffset) {\n return false;\n }\n let newPos = getPosition(ref.current!, selection.focusNode, selection.focusOffset);\n if (!isSamePosition(pos, newPos)) {\n return true;\n }\n }\n };\n\n // macOS supports additional keyboard shortcuts for text editing.\n // We need to handle these manually so they behave consistently with tokens.\n // https://support.apple.com/en-us/102650#text\n let macShortcuts: Record<string, () => boolean | void> = isMac()\n ? {\n 'Control+a': () => {\n return shortcuts.Home();\n },\n 'Control+e': () => {\n return shortcuts.End();\n },\n 'Control+f': () => {\n return shortcuts.ArrowRight();\n },\n 'Control+b': () => {\n return shortcuts.ArrowLeft();\n }\n }\n : {};\n\n let mod = isMac() ? 'Meta' : 'Control';\n let wordModKey = isMac() ? 'Alt' : 'Control';\n let shortcuts: Record<string, () => boolean | void> = {\n ...macShortcuts,\n [`${mod}+z`]: () => {\n // If composing, the browser handles undo natively.\n if (state.isComposing) {\n return false;\n }\n apply(state => state.undo());\n },\n [isMac() ? 'Shift+Meta+z' : 'Control+y']: () => {\n if (state.isComposing) {\n return false;\n }\n apply(state => state.redo());\n },\n ArrowLeft: () => {\n return moveSelection('left', 'character');\n },\n [`${wordModKey}+ArrowLeft`]: () => {\n return moveSelection('left', 'word');\n },\n 'Shift+ArrowLeft': () => {\n return moveSelection('left', 'character', true);\n },\n [`Shift+${wordModKey}+ArrowLeft`]: () => {\n return moveSelection('left', 'word', true);\n },\n ArrowRight: () => {\n return moveSelection('right', 'character');\n },\n [`${wordModKey}+ArrowRight`]: () => {\n return moveSelection('right', 'word');\n },\n 'Shift+ArrowRight': () => {\n return moveSelection('right', 'character', true);\n },\n [`Shift+${wordModKey}+ArrowRight`]: () => {\n return moveSelection('right', 'word', true);\n },\n Home: () => {\n // Browsers do not behave consistently when there are tokens.\n let selection = getSelection(ref.current!);\n if (!selection) {\n return false;\n }\n let boundary = value.findLineBoundary(selection[0], TokenFieldValue.Direction.Backward);\n if (boundary) {\n setCursor(ref.current!, boundary, true);\n return true;\n }\n return false;\n },\n End: () => {\n let selection = getSelection(ref.current!);\n if (!selection) {\n return false;\n }\n let boundary = value.findLineBoundary(selection[1], TokenFieldValue.Direction.Forward);\n if (boundary) {\n setCursor(ref.current!, boundary, true);\n return true;\n }\n return false;\n }\n };\n\n // TODO: user provided onKeyDown currently relies on user provided preventDefault to stop submit\n // maybe can have them specify a format like shortcuts and merge into above?\n let {keyboardProps} = useKeyboard({\n isDisabled: isDisabled || isReadOnly,\n onKeyDown: props.onKeyDown,\n onKeyUp: props.onKeyUp,\n shortcuts: shortcuts,\n allowRepeats: true\n });\n\n let {focusableProps} = useFocusable(props, ref);\n let {labelProps, fieldProps, descriptionProps} = useField({\n ...props,\n labelElementType: 'span'\n });\n\n return {\n labelProps: {\n ...labelProps,\n onClick: () => {\n if (!props.isDisabled) {\n ref.current?.focus();\n\n // Show the focus ring so the user knows where focus went\n setInteractionModality('keyboard');\n }\n }\n },\n descriptionProps,\n tokenFieldProps: mergeProps(focusableProps, keyboardProps, fieldProps, {\n onPaste: props.onPaste,\n onCopy: props.onCopy,\n onCut: props.onCut,\n contentEditable: !isDisabled && !isReadOnly,\n suppressContentEditableWarning: true,\n role,\n 'aria-multiline': multiline,\n 'aria-details': ariaDetails,\n 'aria-readonly': isReadOnly,\n 'aria-disabled': isDisabled,\n style: {whiteSpace: 'pre-wrap'}\n })\n };\n}\n\nfunction indexOfNode(node: Node) {\n let index = 0;\n let n: Node | null = node;\n\n while ((n = n.previousSibling)) {\n index++;\n }\n return index;\n}\n\nexport function getSelection(container: Element): [Position, Position] | null {\n let selection = window.getSelection();\n if (!selection || selection.rangeCount === 0) {\n return null;\n }\n let range = selection.getRangeAt(0);\n return rangeToPositions(container, range);\n}\n\nfunction rangeToPositions(container: Element, range: Range | StaticRange): [Position, Position] {\n let start = getPosition(container, range.startContainer, range.startOffset);\n let end = getPosition(container, range.endContainer, range.endOffset);\n return [start, end];\n}\n\nfunction getPosition(container: Element, node: Node, offset: number): Position {\n if (node === container) {\n return {index: offset, offset: 0};\n }\n\n let originalNode = node;\n while (node.parentNode !== container) {\n node = node.parentNode!;\n }\n\n let index = indexOfNode(node);\n if (node.nodeType === Node.ELEMENT_NODE) {\n let tokenNode = node.childNodes[1];\n let atEnd: boolean;\n let endOffset = 0;\n if (originalNode === tokenNode) {\n // Cursor is inside the token.\n atEnd = offset > 0;\n } else if (originalNode === node) {\n // Cursor is inside the wrapper element.\n atEnd = offset > 1;\n } else {\n // Cursor is on one of the zero width spaces.\n atEnd = originalNode !== tokenNode.previousSibling;\n // If the offset is greater than 1, the browser is trying to insert text into\n // the zero width space node. This will actually end up in the next text node.\n endOffset = atEnd && offset > 1 ? offset - 1 : 0;\n }\n\n offset = atEnd ? (tokenNode?.textContent?.length ?? 0) : 0;\n\n // Several positions are equivalent due to the zero width spaces around tokens.\n // Normalize offset to the end of the preceding text node, or the beginning of the following node.\n if (offset === 0 && node.previousSibling?.nodeType === Node.TEXT_NODE) {\n index--;\n offset = node.previousSibling?.textContent?.length ?? 0;\n } else if (atEnd) {\n index++;\n offset = endOffset;\n }\n }\n return {index, offset};\n}\n\nlet isProgrammaticSelectionChange = Symbol('isProgrammaticSelectionChange');\n\nfunction setCursor(root: Element, pos: Position, fireEvent = false) {\n setTokenFieldSelection(root, pos, pos, fireEvent);\n}\n\nexport function setTokenFieldSelection(\n root: Element,\n start: Position,\n end: Position,\n fireEvent = false\n) {\n let selection = window.getSelection();\n if (selection) {\n let range = createDOMRange(root, start, end);\n root[isProgrammaticSelectionChange] = !fireEvent;\n selection.removeAllRanges();\n selection.addRange(range);\n }\n}\n\nexport function tokenFieldPositionToDOMRange(root: Element, pos: Position): Range {\n return createDOMRange(root, pos, pos);\n}\n\nfunction createDOMRange(root: Element, start: Position, end: Position): Range {\n let range = document.createRange();\n let startChild = root.childNodes[start.index];\n if (!startChild) {\n range.setStart(root, Math.min(root.childNodes.length, start.index));\n } else if (startChild.nodeType === Node.ELEMENT_NODE) {\n // Place the cursor outside the token wrapper element.\n if (start.offset > 0) {\n range.setStartAfter(startChild);\n } else {\n range.setStartBefore(startChild);\n }\n } else {\n range.setStart(startChild, start.offset);\n }\n\n let endChild = root.childNodes[end.index];\n if (!endChild) {\n range.setEnd(root, Math.min(root.childNodes.length, end.index));\n } else if (endChild.nodeType === Node.ELEMENT_NODE) {\n if (end.offset > 0) {\n range.setEndAfter(endChild);\n } else {\n range.setEndBefore(endChild);\n }\n } else {\n range.setEnd(endChild, end.offset);\n }\n return range;\n}\n\nfunction isSamePosition(a: Position, b: Position): boolean {\n return a.index === b.index && a.offset === b.offset;\n}\n\n// Parse and validate segments from clipboard/drag data. Returns null if the data is not valid\n// JSON or does not match the expected shape, so malformed or untrusted data is ignored rather\n// than throwing or being inserted into the field.\nfunction parseSegments(json: string): TokenFieldSegment[] | null {\n try {\n let data = JSON.parse(json);\n if (Array.isArray(data) && data.length > 0 && data.every(isValidSegment)) {\n return data;\n }\n } catch {\n // Ignore invalid clipboard data.\n }\n return null;\n}\n\nfunction isValidSegment(segment: unknown): segment is TokenFieldSegment {\n return (\n typeof segment === 'object' &&\n segment != null &&\n ((segment as TokenFieldSegment).type === 'text' ||\n (segment as TokenFieldSegment).type === 'token') &&\n typeof (segment as TokenFieldSegment).text === 'string'\n );\n}\n\nfunction useSelectionChange(ref: React.RefObject<Element | null>, handler: () => void) {\n useEvent(useRef(typeof document !== 'undefined' ? document : null), 'selectionchange', () => {\n if (ref.current && ref.current[isProgrammaticSelectionChange]) {\n ref.current[isProgrammaticSelectionChange] = false;\n return;\n }\n\n let selection = window.getSelection();\n if (!selection || selection.rangeCount === 0 || !ref.current) {\n return;\n }\n\n let range = selection.getRangeAt(0);\n if (range.intersectsNode(ref.current)) {\n handler();\n }\n });\n}\n\nfunction useMutationTracker(ref: React.RefObject<Element | null>) {\n let mutationTracker = useRef<(() => void) | null>(null);\n\n // Disconnect the mutation observer if the field unmounts mid-composition.\n useLayoutEffect(\n () => () => {\n mutationTracker.current?.();\n mutationTracker.current = null;\n },\n []\n );\n\n return useMemo(\n () => ({\n start() {\n // Android sometimes fires two compositionstart events in a row, without a compositionend.\n // In that case, reuse the existing tracker.\n mutationTracker.current ||= trackMutations(ref.current!);\n },\n stop() {\n mutationTracker.current?.();\n mutationTracker.current = null;\n }\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps - conflicts with compiler\n []\n );\n}\n\n// Tracks mutations to the DOM until the returned function is called,\n// at which point the mutations are reverted.\nfunction trackMutations(element: Element) {\n let mutations: MutationRecord[] = [];\n let observer = new MutationObserver(records => {\n mutations.push(...records);\n });\n\n observer.observe(element, {\n childList: true,\n subtree: true,\n characterData: true,\n characterDataOldValue: true\n });\n\n return () => {\n mutations.push(...observer.takeRecords());\n observer.disconnect();\n\n for (let record of mutations.reverse()) {\n switch (record.type) {\n case 'childList':\n for (let node of record.removedNodes) {\n record.target.insertBefore(node, record.nextSibling);\n }\n for (let node of record.addedNodes) {\n record.target.removeChild(node);\n }\n break;\n case 'characterData':\n record.target.nodeValue = record.oldValue;\n break;\n }\n }\n };\n}\n"],"names":[],"version":3,"file":"useTokenField.cjs.map"}
1
+ {"mappings":"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","sources":["packages/react-aria/src/tokenfield/useTokenField.ts"],"sourcesContent":["/*\n * Copyright 2026 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing\n */\n\nimport {announce} from '../live-announcer/LiveAnnouncer';\nimport {AriaLabelingProps, DOMAttributes, FocusableProps} from '@react-types/shared';\nimport {\n ClipboardEventHandler,\n HTMLAttributes,\n RefObject,\n useCallback,\n useMemo,\n useRef\n} from 'react';\nimport {getActiveElement, nodeContains} from '../utils/shadowdom/DOMFunctions';\nimport {getOwnerDocument} from '../utils/domHelpers';\nimport {isMac} from '../utils/platform';\nimport {mergeProps} from '../utils/mergeProps';\nimport {\n Position,\n SelectedRange,\n TokenFieldProps,\n TokenFieldSegment,\n TokenFieldState,\n TokenFieldValue\n} from 'react-stately/useTokenFieldState';\nimport {setInteractionModality} from '../interactions/useFocusVisible';\nimport {useEvent} from '../utils/useEvent';\nimport {useField} from '../label/useField';\nimport {useFocusable} from '../interactions/useFocusable';\nimport {useKeyboard} from '../interactions/useKeyboard';\nimport {useLayoutEffect} from '../utils/useLayoutEffect';\nimport {useLocale} from '../i18n/I18nProvider';\n\nexport interface AriaTokenFieldProps<T extends TokenFieldValue = TokenFieldValue>\n extends TokenFieldProps<T>, FocusableProps, AriaLabelingProps {\n /**\n * The accessibility role of the token field.\n *\n * @default 'textbox'\n */\n role?: 'textbox' | 'searchbox' | 'combobox';\n /** Whether the token field allows newlines. */\n allowsNewlines?: boolean;\n /** Whether the token field is read only. */\n isReadOnly?: boolean;\n /** Whether the token field is disabled. */\n isDisabled?: boolean;\n /** A function that is called when the user presses the Enter key. */\n onSubmit?: () => void;\n /** Handler that is called when a key is pressed. */\n onKeyDown?: (e: React.KeyboardEvent<HTMLDivElement>) => void;\n /** Handler that is called when a key is released. */\n onKeyUp?: (e: React.KeyboardEvent<HTMLDivElement>) => void;\n /**\n * Handler that is called when the user copies text. See\n * [MDN](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/oncopy).\n */\n onCopy?: ClipboardEventHandler<T>;\n\n /**\n * Handler that is called when the user cuts text. See\n * [MDN](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/oncut).\n */\n onCut?: ClipboardEventHandler<T>;\n\n /**\n * Handler that is called when the user pastes text. See\n * [MDN](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/onpaste).\n */\n onPaste?: ClipboardEventHandler<T>;\n}\n\nexport interface TokenFieldAria {\n /** Props for the token field's input element. */\n tokenFieldProps: HTMLAttributes<HTMLDivElement>;\n /** Props for the text field's visible label element, if any. */\n labelProps: DOMAttributes;\n /** Props for the text field's description element, if any. */\n descriptionProps: DOMAttributes;\n}\n\nconst CLIPBOARD_MIME_TYPE = 'application/vnd.react-aria.tokens+json';\n\n/**\n * Provides the behavior and accessibility implementation for a token field.\n * A token field allows users to enter text with inline tokens.\n *\n * @param props - Props for the token field.\n * @param state - State for the token field, as returned by `useTokenFieldState`.\n */\nexport function useTokenField<T extends TokenFieldValue = TokenFieldValue>(\n props: AriaTokenFieldProps<T>,\n state: TokenFieldState,\n ref: RefObject<HTMLDivElement | null>\n): TokenFieldAria {\n let {\n role = 'textbox',\n allowsNewlines: multiline = false,\n isReadOnly = false,\n isDisabled = false,\n 'aria-details': ariaDetails\n } = props;\n\n let {value} = state;\n let {locale} = useLocale();\n let graphemeSegmenter = useMemo(\n () => new Intl.Segmenter(locale, {granularity: 'grapheme'}),\n [locale]\n );\n let wordSegmenter = useMemo(() => new Intl.Segmenter(locale, {granularity: 'word'}), [locale]);\n\n let dropPosition = useRef<Position | null>(null);\n let transferredData = useRef<TokenFieldSegment[] | null>(null);\n\n let nextValue = useRef<TokenFieldValue | null>(null);\n let apply = (fn: (value: TokenFieldValue) => TokenFieldValue) => {\n state.setValue(value => {\n let newValue = fn(value);\n nextValue.current = newValue;\n return newValue;\n });\n };\n\n // Composition events are not cancelable. The browser will mutate the DOM, making it out of sync with React.\n // To account for this, we prevent React from re-rendering during composition, and track DOM mutations performed\n // by the browser. When composition ends, we revert the DOM to its original state, and re-render with React.\n // Mutating the DOM in any way during composition breaks the IME, causing composition to end unexpectedly.\n // During composition, we still emit updates via onChange to ensure that things like autocomplete work,\n // but we don't actually re-render to the DOM unless the value changes from what we expect (e.g. inserting a completion).\n let mutationTracker = useMutationTracker(ref);\n let startComposition = useCallback(() => {\n mutationTracker.start();\n state.setComposing(true);\n }, [state, mutationTracker]);\n let stopComposition = useCallback(() => {\n mutationTracker.stop();\n state.setComposing(false);\n }, [state, mutationTracker]);\n\n useEvent(ref, 'compositionstart', () => {\n startComposition();\n\n let range = window.getSelection()?.getRangeAt(0);\n if (range) {\n let [start, end] = rangeToPositions(ref.current!, range);\n\n // Normalize the range to ensure it is not inside a token, otherwise the browser\n // will attempt to insert the composed text into the token instead of replacing it.\n let r = createDOMRange(ref.current!, start, end);\n if (r.startContainer !== range.startContainer || r.startOffset !== range.startOffset) {\n range.setStart(r.startContainer, r.startOffset);\n }\n if (r.endContainer !== range.endContainer || r.endOffset !== range.endOffset) {\n range.setEnd(r.endContainer, r.endOffset);\n }\n }\n });\n\n useEvent(ref, 'compositionend', stopComposition);\n\n // If a prop update occurs during composition that doesn't match the expected value,\n // end composition and re-render the controlled value.\n useLayoutEffect(() => {\n if (state.isComposing && value !== nextValue.current) {\n stopComposition();\n }\n nextValue.current = value;\n });\n\n let selectedRange = useRef<SelectedRange | null>(null);\n useLayoutEffect(() => {\n if (ref.current && !state.isComposing && value.selectedRange !== selectedRange.current) {\n // Only move the caret when the field is already focused.\n if (ref.current === getActiveElement(getOwnerDocument(ref.current))) {\n setTokenFieldSelection(ref.current, value.selectedRange);\n announceToken(value);\n }\n selectedRange.current = value.selectedRange;\n }\n });\n\n // Handle text editing commands and prevent browser default behavior.\n useEvent(ref, 'beforeinput', e => {\n // Android sometimes doesn't fire a compositionend event before a regular input event.\n if (state.isComposing && !e.isComposing) {\n stopComposition();\n }\n\n let range = e.getTargetRanges()[0];\n if (!range) {\n let selection = window.getSelection();\n if (!selection || selection.rangeCount === 0) {\n return;\n }\n range = selection.getRangeAt(0);\n }\n let [start, end] = rangeToPositions(ref.current!, range);\n\n // https://www.w3.org/TR/input-events-2/#interface-InputEvent-Attributes\n switch (e.inputType) {\n case 'insertText':\n case 'insertReplacementText':\n case 'insertCompositionText':\n case 'insertFromComposition': // Removed from the spec, but still fired by Safari.\n case 'insertFromPaste':\n case 'insertFromYank':\n case 'insertFromDrop': {\n let data: TokenFieldSegment[] = [{type: 'text', text: e.data ?? ''}];\n if (transferredData.current) {\n data = transferredData.current;\n transferredData.current = null;\n } else if (e.dataTransfer) {\n let parsed = e.dataTransfer.types.includes(CLIPBOARD_MIME_TYPE)\n ? parseSegments(e.dataTransfer.getData(CLIPBOARD_MIME_TYPE))\n : null;\n if (parsed) {\n data = parsed;\n } else if (e.dataTransfer.types.includes('text/plain')) {\n data[0].text = e.dataTransfer.getData('text/plain');\n }\n }\n\n if (e.inputType === 'insertFromDrop' && dropPosition.current) {\n start = end = dropPosition.current;\n dropPosition.current = null;\n }\n\n if (!multiline) {\n for (let segment of data) {\n segment.text = segment.text.replace(/[\\r\\n]+/g, ' ');\n }\n }\n\n apply(tokens =>\n tokens.replaceRangeWithSegments(\n start,\n end,\n data,\n // Don't coalesce paste/drop events with other edits.\n e.inputType === 'insertText' ||\n e.inputType === 'insertCompositionText' ||\n e.inputType === 'insertFromComposition'\n )\n );\n break;\n }\n case 'insertParagraph': {\n if (props.onSubmit) {\n props.onSubmit();\n break;\n }\n // fallthrough\n }\n case 'insertLineBreak': {\n if (multiline) {\n apply(tokens => tokens.replaceRange(start, end, '\\n'));\n }\n break;\n }\n case 'deleteContentBackward':\n case 'deleteContentForward':\n case 'deleteWordBackward':\n case 'deleteWordForward':\n case 'deleteHardLineForward':\n case 'deleteHardLineBackward':\n case 'deleteSoftLineForward':\n case 'deleteSoftLineBackward':\n case 'deleteContent':\n case 'deleteByCut':\n case 'deleteCompositionText': {\n if (!range.collapsed && !isSamePosition(start, end)) {\n apply(tokens => tokens.replaceRange(start, end, ''));\n break;\n }\n\n switch (e.inputType) {\n case 'deleteContentBackward': {\n apply(tokens =>\n tokens.delete(start, graphemeSegmenter, TokenFieldValue.Direction.Backward)\n );\n break;\n }\n case 'deleteContentForward':\n apply(tokens =>\n tokens.delete(start, graphemeSegmenter, TokenFieldValue.Direction.Forward)\n );\n break;\n case 'deleteWordBackward': {\n apply(tokens =>\n tokens.delete(start, wordSegmenter, TokenFieldValue.Direction.Backward)\n );\n break;\n }\n case 'deleteWordForward':\n apply(tokens => tokens.delete(start, wordSegmenter, TokenFieldValue.Direction.Forward));\n break;\n case 'deleteHardLineForward':\n case 'deleteSoftLineForward': // TODO: this usually deletes to the nearest *visual* line break rather than a hard break\n apply(tokens => tokens.deleteLine(start, TokenFieldValue.Direction.Forward));\n break;\n case 'deleteHardLineBackward':\n case 'deleteSoftLineBackward':\n apply(tokens => tokens.deleteLine(start, TokenFieldValue.Direction.Backward));\n break;\n }\n break;\n }\n case 'deleteByDrag': {\n apply(tokens => {\n let endOffset =\n start.index === end.index ? end.offset : tokens.segments[start.index].text.length;\n let change = tokens.replaceRange(start, end, '');\n if (\n dropPosition.current &&\n dropPosition.current.index === start.index &&\n dropPosition.current.offset >= start.offset\n ) {\n dropPosition.current.offset -= endOffset - start.offset;\n }\n\n return change;\n });\n break;\n }\n }\n\n e.preventDefault();\n });\n\n let writeClipboardData = (e: ClipboardEvent | DragEvent) => {\n if ('clipboardData' in e) {\n e.preventDefault();\n }\n let selection = getSelection(ref.current!);\n if (!selection) {\n return;\n }\n let [start, end] = selection;\n let slice = value.slice(start, end);\n let dataTransfer = 'clipboardData' in e ? e.clipboardData : e.dataTransfer;\n dataTransfer?.setData(CLIPBOARD_MIME_TYPE, JSON.stringify(slice.segments));\n dataTransfer?.setData('text/plain', slice.toString());\n\n if (e.type === 'cut') {\n apply(tokens => tokens.replaceRange(start, end, '', false));\n }\n };\n\n useEvent(ref, 'copy', writeClipboardData);\n useEvent(ref, 'cut', writeClipboardData);\n useEvent(ref, 'dragstart', writeClipboardData);\n useEvent(ref, 'paste', e => {\n // Safari doesn't pass the custom clipboard data type to beforeinput dataTransfer so we handle it here.\n if (e.clipboardData && e.clipboardData.types.includes(CLIPBOARD_MIME_TYPE)) {\n transferredData.current = parseSegments(e.clipboardData.getData(CLIPBOARD_MIME_TYPE));\n }\n });\n\n // Store the cursor position on drop so we know where to insert when the insertFromDrop event occurs.\n useEvent(ref, 'drop', e => {\n if (typeof document.caretPositionFromPoint === 'function') {\n let pos = document.caretPositionFromPoint(e.clientX, e.clientY);\n if (pos) {\n dropPosition.current = getPosition(ref.current!, pos.offsetNode, pos.offset);\n }\n } else if (typeof document.caretRangeFromPoint === 'function') {\n let range = document.caretRangeFromPoint(e.clientX, e.clientY);\n if (range) {\n dropPosition.current = getPosition(ref.current!, range.startContainer, range.startOffset);\n }\n }\n\n if (e.dataTransfer && e.dataTransfer.types.includes(CLIPBOARD_MIME_TYPE)) {\n transferredData.current = parseSegments(e.dataTransfer.getData(CLIPBOARD_MIME_TYPE));\n }\n });\n\n useSelectionChange(ref, () => {\n if (state.isComposing) {\n return;\n }\n\n value.endCoalescing();\n\n // When the cursor moves next to a token, announce it.\n // Otherwise the screen reader will only announce the first/last character.\n let range = getSelectedRange(ref.current!);\n if (!range) {\n return;\n }\n\n announceToken(value, range);\n\n // Update the selected range in the value.\n state.setValue(value => value.withSelectedRange(range));\n });\n\n // Clear selection on blur.\n useEvent(ref, 'blur', e => {\n if (!e.isTrusted) {\n return;\n }\n\n let selection = window.getSelection();\n if (ref.current && selection && selection.containsNode(ref.current, true)) {\n selection.removeAllRanges();\n state.setValue(value =>\n value.withSelectedRange(new TokenFieldValue.SelectedRange(value.caretPosition))\n );\n }\n });\n\n // Override the default triple click behavior to ensure that tokens get selected.\n // Some browsers only select the text between tokens instead of the entire line.\n useEvent(ref, 'mousedown', e => {\n if (e.detail === 3) {\n let selection = getSelection(ref.current!);\n if (!selection) {\n return;\n }\n\n let start = value.findLineBoundary(selection[0], TokenFieldValue.Direction.Backward);\n let end = value.findLineBoundary(selection[1], TokenFieldValue.Direction.Forward);\n if (start && end) {\n e.preventDefault();\n setTokenFieldSelection(ref.current!, new TokenFieldValue.SelectedRange(start, end), true);\n }\n }\n });\n\n let moveSelection = (\n direction: 'left' | 'right',\n granularity: 'character' | 'word',\n extend = false\n ) => {\n let selection = window.getSelection();\n if (!selection || selection.rangeCount === 0 || !selection.focusNode || !selection.anchorNode) {\n return false;\n }\n\n // Pressing an arrow with a non-empty selection collapses it to the corresponding edge.\n // The browser handles this natively.\n if (!extend && !selection.isCollapsed) {\n return false;\n }\n\n // Move the caret using the browser's native caret movement (Selection.modify) so that\n // bidirectional text is handled correctly. Repeat until the position actually changes\n // to account for the zero width spaces around tokens.\n let pos = getPosition(ref.current!, selection.focusNode, selection.focusOffset);\n while (true) {\n let {focusNode, focusOffset} = selection;\n selection.modify(extend ? 'extend' : 'move', direction, granularity);\n if (selection.focusNode === focusNode && selection.focusOffset === focusOffset) {\n return false;\n }\n let newPos = getPosition(ref.current!, selection.focusNode, selection.focusOffset);\n if (!isSamePosition(pos, newPos)) {\n return true;\n }\n }\n };\n\n // macOS supports additional keyboard shortcuts for text editing.\n // We need to handle these manually so they behave consistently with tokens.\n // https://support.apple.com/en-us/102650#text\n let macShortcuts: Record<string, () => boolean | void> = isMac()\n ? {\n 'Control+a': () => {\n return shortcuts.Home();\n },\n 'Control+e': () => {\n return shortcuts.End();\n },\n 'Control+f': () => {\n return shortcuts.ArrowRight();\n },\n 'Control+b': () => {\n return shortcuts.ArrowLeft();\n }\n }\n : {};\n\n let mod = isMac() ? 'Meta' : 'Control';\n let wordModKey = isMac() ? 'Alt' : 'Control';\n let shortcuts: Record<string, () => boolean | void> = {\n ...macShortcuts,\n [`${mod}+z`]: () => {\n // If composing, the browser handles undo natively.\n if (state.isComposing) {\n return false;\n }\n apply(state => state.undo());\n },\n [isMac() ? 'Shift+Meta+z' : 'Control+y']: () => {\n if (state.isComposing) {\n return false;\n }\n apply(state => state.redo());\n },\n ArrowLeft: () => {\n return moveSelection('left', 'character');\n },\n [`${wordModKey}+ArrowLeft`]: () => {\n return moveSelection('left', 'word');\n },\n 'Shift+ArrowLeft': () => {\n return moveSelection('left', 'character', true);\n },\n [`Shift+${wordModKey}+ArrowLeft`]: () => {\n return moveSelection('left', 'word', true);\n },\n ArrowRight: () => {\n return moveSelection('right', 'character');\n },\n [`${wordModKey}+ArrowRight`]: () => {\n return moveSelection('right', 'word');\n },\n 'Shift+ArrowRight': () => {\n return moveSelection('right', 'character', true);\n },\n [`Shift+${wordModKey}+ArrowRight`]: () => {\n return moveSelection('right', 'word', true);\n },\n Home: () => {\n // Browsers do not behave consistently when there are tokens.\n let selection = getSelection(ref.current!);\n if (!selection) {\n return false;\n }\n let boundary = value.findLineBoundary(selection[0], TokenFieldValue.Direction.Backward);\n if (boundary) {\n setCursor(ref.current!, boundary, true);\n return true;\n }\n return false;\n },\n End: () => {\n let selection = getSelection(ref.current!);\n if (!selection) {\n return false;\n }\n let boundary = value.findLineBoundary(selection[1], TokenFieldValue.Direction.Forward);\n if (boundary) {\n setCursor(ref.current!, boundary, true);\n return true;\n }\n return false;\n }\n };\n\n // TODO: user provided onKeyDown currently relies on user provided preventDefault to stop submit\n // maybe can have them specify a format like shortcuts and merge into above?\n let {keyboardProps} = useKeyboard({\n isDisabled: isDisabled || isReadOnly,\n onKeyDown: props.onKeyDown,\n onKeyUp: props.onKeyUp,\n shortcuts: shortcuts,\n allowRepeats: true\n });\n\n let {focusableProps} = useFocusable(props, ref);\n let {labelProps, fieldProps, descriptionProps} = useField({\n ...props,\n labelElementType: 'span'\n });\n\n return {\n labelProps: {\n ...labelProps,\n onClick: () => {\n if (!props.isDisabled) {\n ref.current?.focus();\n\n // Show the focus ring so the user knows where focus went\n setInteractionModality('keyboard');\n }\n }\n },\n descriptionProps,\n tokenFieldProps: mergeProps(focusableProps, keyboardProps, fieldProps, {\n onPaste: props.onPaste,\n onCopy: props.onCopy,\n onCut: props.onCut,\n contentEditable: !isDisabled && !isReadOnly,\n suppressContentEditableWarning: true,\n role,\n 'aria-multiline': multiline,\n 'aria-details': ariaDetails,\n 'aria-readonly': isReadOnly,\n 'aria-disabled': isDisabled,\n style: {whiteSpace: 'pre-wrap'}\n })\n };\n}\n\nfunction indexOfNode(node: Node) {\n let index = 0;\n let n: Node | null = node;\n\n while ((n = n.previousSibling)) {\n index++;\n }\n return index;\n}\n\nexport function getSelection(container: Element): [Position, Position] | null {\n let selection = window.getSelection();\n if (!selection || selection.rangeCount === 0) {\n return null;\n }\n let range = selection.getRangeAt(0);\n return rangeToPositions(container, range);\n}\n\nexport function getSelectedRange(container: Element) {\n let selection = window.getSelection();\n if (\n !selection ||\n !selection.anchorNode ||\n !selection.focusNode ||\n !nodeContains(container, selection.anchorNode) ||\n !nodeContains(container, selection.focusNode)\n ) {\n return null;\n }\n let anchor = getPosition(container, selection.anchorNode, selection.anchorOffset, false);\n let current = getPosition(\n container,\n selection.focusNode,\n selection.focusOffset,\n !selection.isCollapsed\n );\n return new TokenFieldValue.SelectedRange(anchor, current);\n}\n\nfunction rangeToPositions(container: Element, range: Range | StaticRange): [Position, Position] {\n let start = getPosition(container, range.startContainer, range.startOffset, false);\n let end = getPosition(container, range.endContainer, range.endOffset, !range.collapsed);\n return [start, end];\n}\n\nfunction getPosition(container: Element, node: Node, offset: number, isRangeEnd = false): Position {\n if (node === container) {\n return {index: offset, offset: 0};\n }\n\n let originalNode = node;\n while (node.parentNode !== container) {\n node = node.parentNode!;\n }\n\n let index = indexOfNode(node);\n if (node.nodeType === Node.ELEMENT_NODE) {\n let tokenNode = node.childNodes[1];\n let atEnd: boolean;\n let endOffset = 0;\n if (originalNode === tokenNode) {\n // Cursor is inside the token.\n atEnd = isRangeEnd || offset > 0;\n } else if (originalNode === node) {\n // Cursor is inside the wrapper element.\n atEnd = offset > 1;\n } else {\n // Cursor is on one of the zero width spaces.\n atEnd = originalNode !== tokenNode.previousSibling;\n // If the offset is greater than 1, the browser is trying to insert text into\n // the zero width space node. This will actually end up in the next text node.\n endOffset = atEnd && offset > 1 ? offset - 1 : 0;\n }\n\n offset = atEnd ? (tokenNode?.textContent?.length ?? 0) : 0;\n\n // Several positions are equivalent due to the zero width spaces around tokens.\n // Normalize offset to the end of the preceding text node, or the beginning of the following node.\n if (offset === 0 && node.previousSibling?.nodeType === Node.TEXT_NODE) {\n index--;\n offset = node.previousSibling?.textContent?.length ?? 0;\n } else if (atEnd) {\n index++;\n offset = endOffset;\n }\n }\n return {index, offset};\n}\n\nlet isProgrammaticSelectionChange = Symbol('isProgrammaticSelectionChange');\n\nfunction setCursor(root: Element, pos: Position, fireEvent = false) {\n setTokenFieldSelection(root, new TokenFieldValue.SelectedRange(pos), fireEvent);\n}\n\nexport function setTokenFieldSelection(\n root: Element,\n selectedRange: SelectedRange,\n fireEvent = false\n) {\n let selection = window.getSelection();\n if (selection) {\n // Use setBaseAndExtent to preserve the selection direction. A plain Range +\n // addRange always produces a forward selection and collapses when the\n // anchor comes after the current position (backward selections).\n let [anchorNode, anchorOffset] = getDOMPosition(root, selectedRange.anchor);\n let [focusNode, focusOffset] = getDOMPosition(root, selectedRange.current);\n root[isProgrammaticSelectionChange] = !fireEvent;\n\n // Only set selection if it has changed, because this can clobber the browser's selection direction.\n if (\n selection.anchorNode !== anchorNode ||\n selection.anchorOffset !== anchorOffset ||\n selection.focusNode !== focusNode ||\n selection.focusOffset !== focusOffset\n ) {\n selection.setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset);\n }\n }\n}\n\nexport function tokenFieldPositionToDOMRange(root: Element, pos: Position): Range {\n // Unlike createDOMRange (used for caret/selection placement), this range is only\n // measured via getBoundingClientRect to position things like an autocomplete popover.\n // Place the endpoints inside the token's zero width space wrappers so the range has a\n // valid rect at the token, rather than a collapsed root-level position.\n let range = document.createRange();\n let [startContainer, startOffset] = getDOMRectPosition(root, pos);\n range.setStart(startContainer, startOffset);\n range.setEnd(startContainer, startOffset);\n return range;\n}\n\nfunction getDOMRectPosition(root: Element, pos: Position): [Node, number] {\n let child = root.childNodes[pos.index];\n if (child && child.nodeType === Node.ELEMENT_NODE) {\n // Place the position inside the zero width space wrappers around the token.\n if (pos.offset > 0) {\n return [child.lastChild!, 1];\n } else {\n return [child.firstChild!, 0];\n }\n }\n return getDOMPosition(root, pos);\n}\n\nfunction createDOMRange(root: Element, start: Position, end: Position): Range {\n let range = document.createRange();\n let [startContainer, startOffset] = getDOMPosition(root, start);\n let [endContainer, endOffset] = getDOMPosition(root, end);\n range.setStart(startContainer, startOffset);\n range.setEnd(endContainer, endOffset);\n return range;\n}\n\nfunction getDOMPosition(root: Element, pos: Position): [Node, number] {\n let index = Math.max(0, Math.min(root.childNodes.length, pos.index));\n let child = root.childNodes[index];\n if (!child) {\n return [root, index];\n } else if (child.nodeType === Node.ELEMENT_NODE) {\n // Place the cursor outside the token wrapper element.\n // This is necessary for composition events.\n if (pos.offset > 0) {\n return [root, index + 1];\n } else {\n return [root, index];\n }\n } else {\n let offset = Math.max(0, Math.min(child.textContent?.length ?? 0, pos.offset));\n return [child, offset];\n }\n}\n\nfunction isSamePosition(a: Position, b: Position): boolean {\n return a.index === b.index && a.offset === b.offset;\n}\n\n// Parse and validate segments from clipboard/drag data. Returns null if the data is not valid\n// JSON or does not match the expected shape, so malformed or untrusted data is ignored rather\n// than throwing or being inserted into the field.\nfunction parseSegments(json: string): TokenFieldSegment[] | null {\n try {\n let data = JSON.parse(json);\n if (Array.isArray(data) && data.length > 0 && data.every(isValidSegment)) {\n return data;\n }\n } catch {\n // Ignore invalid clipboard data.\n }\n return null;\n}\n\nfunction isValidSegment(segment: unknown): segment is TokenFieldSegment {\n return (\n typeof segment === 'object' &&\n segment != null &&\n ((segment as TokenFieldSegment).type === 'text' ||\n (segment as TokenFieldSegment).type === 'token') &&\n typeof (segment as TokenFieldSegment).text === 'string'\n );\n}\n\nfunction useSelectionChange(ref: React.RefObject<Element | null>, handler: () => void) {\n useEvent(useRef(typeof document !== 'undefined' ? document : null), 'selectionchange', () => {\n if (ref.current && ref.current[isProgrammaticSelectionChange]) {\n ref.current[isProgrammaticSelectionChange] = false;\n return;\n }\n\n let selection = window.getSelection();\n if (!selection || selection.rangeCount === 0 || !ref.current) {\n return;\n }\n\n let range = selection.getRangeAt(0);\n if (range.intersectsNode(ref.current)) {\n handler();\n }\n });\n}\n\nfunction useMutationTracker(ref: React.RefObject<Element | null>) {\n let mutationTracker = useRef<(() => void) | null>(null);\n\n // Disconnect the mutation observer if the field unmounts mid-composition.\n useLayoutEffect(\n () => () => {\n mutationTracker.current?.();\n mutationTracker.current = null;\n },\n []\n );\n\n return useMemo(\n () => ({\n start() {\n // Android sometimes fires two compositionstart events in a row, without a compositionend.\n // In that case, reuse the existing tracker.\n mutationTracker.current ||= trackMutations(ref.current!);\n },\n stop() {\n mutationTracker.current?.();\n mutationTracker.current = null;\n }\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps - conflicts with compiler\n []\n );\n}\n\n// Tracks mutations to the DOM until the returned function is called,\n// at which point the mutations are reverted.\nfunction trackMutations(element: Element) {\n let mutations: MutationRecord[] = [];\n let observer = new MutationObserver(records => {\n mutations.push(...records);\n });\n\n observer.observe(element, {\n childList: true,\n subtree: true,\n characterData: true,\n characterDataOldValue: true\n });\n\n return () => {\n mutations.push(...observer.takeRecords());\n observer.disconnect();\n\n for (let record of mutations.reverse()) {\n switch (record.type) {\n case 'childList':\n for (let node of record.removedNodes) {\n record.target.insertBefore(node, record.nextSibling);\n }\n for (let node of record.addedNodes) {\n record.target.removeChild(node);\n }\n break;\n case 'characterData':\n record.target.nodeValue = record.oldValue;\n break;\n }\n }\n };\n}\n\nfunction announceToken(value: TokenFieldValue, range = value.selectedRange) {\n if (range.isCollapsed) {\n // Announce adjacent tokens.\n let segment = value.segments[range.current.index];\n if (segment && segment.type !== 'token') {\n if (range.current.offset === 0) {\n segment = value.segments[range.current.index - 1];\n } else if (range.current.offset === segment.text.length) {\n segment = value.segments[range.current.index + 1];\n }\n }\n if (segment?.type === 'token') {\n announce(segment.text, 'assertive');\n }\n } else {\n // Announce token if it is the only thing selected.\n let selected = value.slice(range.start, range.end).segments;\n if (selected.length === 1 && selected[0].type === 'token') {\n announce(selected[0].text, 'assertive');\n }\n }\n}\n"],"names":[],"version":3,"file":"useTokenField.cjs.map"}