@react-aria/autocomplete 3.0.0-alpha.9 → 3.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. package/dist/ar-AE.main.js +6 -0
  2. package/dist/ar-AE.main.js.map +1 -0
  3. package/dist/ar-AE.mjs +8 -0
  4. package/dist/ar-AE.module.js +8 -0
  5. package/dist/ar-AE.module.js.map +1 -0
  6. package/dist/bg-BG.main.js +6 -0
  7. package/dist/bg-BG.main.js.map +1 -0
  8. package/dist/bg-BG.mjs +8 -0
  9. package/dist/bg-BG.module.js +8 -0
  10. package/dist/bg-BG.module.js.map +1 -0
  11. package/dist/cs-CZ.main.js +6 -0
  12. package/dist/cs-CZ.main.js.map +1 -0
  13. package/dist/cs-CZ.mjs +8 -0
  14. package/dist/cs-CZ.module.js +8 -0
  15. package/dist/cs-CZ.module.js.map +1 -0
  16. package/dist/da-DK.main.js +6 -0
  17. package/dist/da-DK.main.js.map +1 -0
  18. package/dist/da-DK.mjs +8 -0
  19. package/dist/da-DK.module.js +8 -0
  20. package/dist/da-DK.module.js.map +1 -0
  21. package/dist/de-DE.main.js +6 -0
  22. package/dist/de-DE.main.js.map +1 -0
  23. package/dist/de-DE.mjs +8 -0
  24. package/dist/de-DE.module.js +8 -0
  25. package/dist/de-DE.module.js.map +1 -0
  26. package/dist/el-GR.main.js +6 -0
  27. package/dist/el-GR.main.js.map +1 -0
  28. package/dist/el-GR.mjs +8 -0
  29. package/dist/el-GR.module.js +8 -0
  30. package/dist/el-GR.module.js.map +1 -0
  31. package/dist/en-US.main.js +6 -0
  32. package/dist/en-US.main.js.map +1 -0
  33. package/dist/en-US.mjs +8 -0
  34. package/dist/en-US.module.js +8 -0
  35. package/dist/en-US.module.js.map +1 -0
  36. package/dist/es-ES.main.js +6 -0
  37. package/dist/es-ES.main.js.map +1 -0
  38. package/dist/es-ES.mjs +8 -0
  39. package/dist/es-ES.module.js +8 -0
  40. package/dist/es-ES.module.js.map +1 -0
  41. package/dist/et-EE.main.js +6 -0
  42. package/dist/et-EE.main.js.map +1 -0
  43. package/dist/et-EE.mjs +8 -0
  44. package/dist/et-EE.module.js +8 -0
  45. package/dist/et-EE.module.js.map +1 -0
  46. package/dist/fi-FI.main.js +6 -0
  47. package/dist/fi-FI.main.js.map +1 -0
  48. package/dist/fi-FI.mjs +8 -0
  49. package/dist/fi-FI.module.js +8 -0
  50. package/dist/fi-FI.module.js.map +1 -0
  51. package/dist/fr-FR.main.js +6 -0
  52. package/dist/fr-FR.main.js.map +1 -0
  53. package/dist/fr-FR.mjs +8 -0
  54. package/dist/fr-FR.module.js +8 -0
  55. package/dist/fr-FR.module.js.map +1 -0
  56. package/dist/he-IL.main.js +6 -0
  57. package/dist/he-IL.main.js.map +1 -0
  58. package/dist/he-IL.mjs +8 -0
  59. package/dist/he-IL.module.js +8 -0
  60. package/dist/he-IL.module.js.map +1 -0
  61. package/dist/hr-HR.main.js +6 -0
  62. package/dist/hr-HR.main.js.map +1 -0
  63. package/dist/hr-HR.mjs +8 -0
  64. package/dist/hr-HR.module.js +8 -0
  65. package/dist/hr-HR.module.js.map +1 -0
  66. package/dist/hu-HU.main.js +6 -0
  67. package/dist/hu-HU.main.js.map +1 -0
  68. package/dist/hu-HU.mjs +8 -0
  69. package/dist/hu-HU.module.js +8 -0
  70. package/dist/hu-HU.module.js.map +1 -0
  71. package/dist/import.mjs +19 -0
  72. package/dist/intlStrings.main.js +108 -0
  73. package/dist/intlStrings.main.js.map +1 -0
  74. package/dist/intlStrings.mjs +110 -0
  75. package/dist/intlStrings.module.js +110 -0
  76. package/dist/intlStrings.module.js.map +1 -0
  77. package/dist/it-IT.main.js +6 -0
  78. package/dist/it-IT.main.js.map +1 -0
  79. package/dist/it-IT.mjs +8 -0
  80. package/dist/it-IT.module.js +8 -0
  81. package/dist/it-IT.module.js.map +1 -0
  82. package/dist/ja-JP.main.js +6 -0
  83. package/dist/ja-JP.main.js.map +1 -0
  84. package/dist/ja-JP.mjs +8 -0
  85. package/dist/ja-JP.module.js +8 -0
  86. package/dist/ja-JP.module.js.map +1 -0
  87. package/dist/ko-KR.main.js +6 -0
  88. package/dist/ko-KR.main.js.map +1 -0
  89. package/dist/ko-KR.mjs +8 -0
  90. package/dist/ko-KR.module.js +8 -0
  91. package/dist/ko-KR.module.js.map +1 -0
  92. package/dist/lt-LT.main.js +6 -0
  93. package/dist/lt-LT.main.js.map +1 -0
  94. package/dist/lt-LT.mjs +8 -0
  95. package/dist/lt-LT.module.js +8 -0
  96. package/dist/lt-LT.module.js.map +1 -0
  97. package/dist/lv-LV.main.js +6 -0
  98. package/dist/lv-LV.main.js.map +1 -0
  99. package/dist/lv-LV.mjs +8 -0
  100. package/dist/lv-LV.module.js +8 -0
  101. package/dist/lv-LV.module.js.map +1 -0
  102. package/dist/main.js +16 -42
  103. package/dist/main.js.map +1 -1
  104. package/dist/module.js +14 -42
  105. package/dist/module.js.map +1 -1
  106. package/dist/nb-NO.main.js +6 -0
  107. package/dist/nb-NO.main.js.map +1 -0
  108. package/dist/nb-NO.mjs +8 -0
  109. package/dist/nb-NO.module.js +8 -0
  110. package/dist/nb-NO.module.js.map +1 -0
  111. package/dist/nl-NL.main.js +6 -0
  112. package/dist/nl-NL.main.js.map +1 -0
  113. package/dist/nl-NL.mjs +8 -0
  114. package/dist/nl-NL.module.js +8 -0
  115. package/dist/nl-NL.module.js.map +1 -0
  116. package/dist/pl-PL.main.js +6 -0
  117. package/dist/pl-PL.main.js.map +1 -0
  118. package/dist/pl-PL.mjs +8 -0
  119. package/dist/pl-PL.module.js +8 -0
  120. package/dist/pl-PL.module.js.map +1 -0
  121. package/dist/pt-BR.main.js +6 -0
  122. package/dist/pt-BR.main.js.map +1 -0
  123. package/dist/pt-BR.mjs +8 -0
  124. package/dist/pt-BR.module.js +8 -0
  125. package/dist/pt-BR.module.js.map +1 -0
  126. package/dist/pt-PT.main.js +6 -0
  127. package/dist/pt-PT.main.js.map +1 -0
  128. package/dist/pt-PT.mjs +8 -0
  129. package/dist/pt-PT.module.js +8 -0
  130. package/dist/pt-PT.module.js.map +1 -0
  131. package/dist/ro-RO.main.js +6 -0
  132. package/dist/ro-RO.main.js.map +1 -0
  133. package/dist/ro-RO.mjs +8 -0
  134. package/dist/ro-RO.module.js +8 -0
  135. package/dist/ro-RO.module.js.map +1 -0
  136. package/dist/ru-RU.main.js +6 -0
  137. package/dist/ru-RU.main.js.map +1 -0
  138. package/dist/ru-RU.mjs +8 -0
  139. package/dist/ru-RU.module.js +8 -0
  140. package/dist/ru-RU.module.js.map +1 -0
  141. package/dist/sk-SK.main.js +6 -0
  142. package/dist/sk-SK.main.js.map +1 -0
  143. package/dist/sk-SK.mjs +8 -0
  144. package/dist/sk-SK.module.js +8 -0
  145. package/dist/sk-SK.module.js.map +1 -0
  146. package/dist/sl-SI.main.js +6 -0
  147. package/dist/sl-SI.main.js.map +1 -0
  148. package/dist/sl-SI.mjs +8 -0
  149. package/dist/sl-SI.module.js +8 -0
  150. package/dist/sl-SI.module.js.map +1 -0
  151. package/dist/sr-SP.main.js +6 -0
  152. package/dist/sr-SP.main.js.map +1 -0
  153. package/dist/sr-SP.mjs +8 -0
  154. package/dist/sr-SP.module.js +8 -0
  155. package/dist/sr-SP.module.js.map +1 -0
  156. package/dist/sv-SE.main.js +6 -0
  157. package/dist/sv-SE.main.js.map +1 -0
  158. package/dist/sv-SE.mjs +8 -0
  159. package/dist/sv-SE.module.js +8 -0
  160. package/dist/sv-SE.module.js.map +1 -0
  161. package/dist/tr-TR.main.js +6 -0
  162. package/dist/tr-TR.main.js.map +1 -0
  163. package/dist/tr-TR.mjs +8 -0
  164. package/dist/tr-TR.module.js +8 -0
  165. package/dist/tr-TR.module.js.map +1 -0
  166. package/dist/types.d.ts +69 -15
  167. package/dist/types.d.ts.map +1 -1
  168. package/dist/uk-UA.main.js +6 -0
  169. package/dist/uk-UA.main.js.map +1 -0
  170. package/dist/uk-UA.mjs +8 -0
  171. package/dist/uk-UA.module.js +8 -0
  172. package/dist/uk-UA.module.js.map +1 -0
  173. package/dist/useAutocomplete.main.js +273 -0
  174. package/dist/useAutocomplete.main.js.map +1 -0
  175. package/dist/useAutocomplete.mjs +268 -0
  176. package/dist/useAutocomplete.module.js +268 -0
  177. package/dist/useAutocomplete.module.js.map +1 -0
  178. package/dist/useSearchAutocomplete.main.js +73 -0
  179. package/dist/useSearchAutocomplete.main.js.map +1 -0
  180. package/dist/useSearchAutocomplete.mjs +68 -0
  181. package/dist/useSearchAutocomplete.module.js +68 -0
  182. package/dist/useSearchAutocomplete.module.js.map +1 -0
  183. package/dist/zh-CN.main.js +6 -0
  184. package/dist/zh-CN.main.js.map +1 -0
  185. package/dist/zh-CN.mjs +8 -0
  186. package/dist/zh-CN.module.js +8 -0
  187. package/dist/zh-CN.module.js.map +1 -0
  188. package/dist/zh-TW.main.js +6 -0
  189. package/dist/zh-TW.main.js.map +1 -0
  190. package/dist/zh-TW.mjs +8 -0
  191. package/dist/zh-TW.module.js +8 -0
  192. package/dist/zh-TW.module.js.map +1 -0
  193. package/package.json +23 -21
  194. package/src/index.ts +5 -1
  195. package/src/useAutocomplete.ts +364 -0
  196. package/src/useSearchAutocomplete.ts +62 -27
@@ -0,0 +1,273 @@
1
+ var $fbc7b37667f52272$exports = require("./intlStrings.main.js");
2
+ var $4yz2I$reactariautils = require("@react-aria/utils");
3
+ var $4yz2I$reactariafocus = require("@react-aria/focus");
4
+ var $4yz2I$reactariainteractions = require("@react-aria/interactions");
5
+ var $4yz2I$react = require("react");
6
+ var $4yz2I$reactariai18n = require("@react-aria/i18n");
7
+
8
+
9
+ function $parcel$interopDefault(a) {
10
+ return a && a.__esModule ? a.default : a;
11
+ }
12
+
13
+ function $parcel$export(e, n, v, s) {
14
+ Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
15
+ }
16
+
17
+ $parcel$export(module.exports, "useAutocomplete", () => $d43aec1bf2be84e8$export$1e40b3ca02d92d21);
18
+ /*
19
+ * Copyright 2024 Adobe. All rights reserved.
20
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
21
+ * you may not use this file except in compliance with the License. You may obtain a copy
22
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
23
+ *
24
+ * Unless required by applicable law or agreed to in writing, software distributed under
25
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
26
+ * OF ANY KIND, either express or implied. See the License for the specific language
27
+ * governing permissions and limitations under the License.
28
+ */
29
+
30
+
31
+
32
+
33
+
34
+ function $d43aec1bf2be84e8$export$1e40b3ca02d92d21(props, state) {
35
+ let { inputRef: inputRef, collectionRef: collectionRef, filter: filter, disableAutoFocusFirst: disableAutoFocusFirst = false } = props;
36
+ let collectionId = (0, $4yz2I$reactariautils.useId)();
37
+ let timeout = (0, $4yz2I$react.useRef)(undefined);
38
+ let delayNextActiveDescendant = (0, $4yz2I$react.useRef)(false);
39
+ let queuedActiveDescendant = (0, $4yz2I$react.useRef)(null);
40
+ let lastCollectionNode = (0, $4yz2I$react.useRef)(null);
41
+ // For mobile screen readers, we don't want virtual focus, instead opting to disable FocusScope's restoreFocus and manually
42
+ // moving focus back to the subtriggers
43
+ let shouldUseVirtualFocus = (0, $4yz2I$reactariainteractions.getInteractionModality)() !== 'virtual';
44
+ (0, $4yz2I$react.useEffect)(()=>{
45
+ return ()=>clearTimeout(timeout.current);
46
+ }, []);
47
+ let updateActiveDescendant = (0, $4yz2I$reactariautils.useEffectEvent)((e)=>{
48
+ // Ensure input is focused if the user clicks on the collection directly.
49
+ if (!e.isTrusted && shouldUseVirtualFocus && inputRef.current && (0, $4yz2I$reactariautils.getActiveElement)((0, $4yz2I$reactariautils.getOwnerDocument)(inputRef.current)) !== inputRef.current) inputRef.current.focus();
50
+ let target = e.target;
51
+ if (e.isTrusted || !target || queuedActiveDescendant.current === target.id) return;
52
+ clearTimeout(timeout.current);
53
+ if (target !== collectionRef.current) {
54
+ if (delayNextActiveDescendant.current) {
55
+ queuedActiveDescendant.current = target.id;
56
+ timeout.current = setTimeout(()=>{
57
+ state.setFocusedNodeId(target.id);
58
+ }, 500);
59
+ } else {
60
+ queuedActiveDescendant.current = target.id;
61
+ state.setFocusedNodeId(target.id);
62
+ }
63
+ } else {
64
+ queuedActiveDescendant.current = null;
65
+ state.setFocusedNodeId(null);
66
+ }
67
+ delayNextActiveDescendant.current = false;
68
+ });
69
+ let callbackRef = (0, $4yz2I$react.useCallback)((collectionNode)=>{
70
+ var _lastCollectionNode_current;
71
+ if (collectionNode != null) {
72
+ var // When typing forward, we want to delay the setting of active descendant to not interrupt the native screen reader announcement
73
+ // of the letter you just typed. If we recieve another focus event then we clear the queued update
74
+ // We track lastCollectionNode to do proper cleanup since callbackRefs just pass null when unmounting. This also handles
75
+ // React 19's extra call of the callback ref in strict mode
76
+ _lastCollectionNode_current1;
77
+ (_lastCollectionNode_current1 = lastCollectionNode.current) === null || _lastCollectionNode_current1 === void 0 ? void 0 : _lastCollectionNode_current1.removeEventListener('focusin', updateActiveDescendant);
78
+ lastCollectionNode.current = collectionNode;
79
+ collectionNode.addEventListener('focusin', updateActiveDescendant);
80
+ } else (_lastCollectionNode_current = lastCollectionNode.current) === null || _lastCollectionNode_current === void 0 ? void 0 : _lastCollectionNode_current.removeEventListener('focusin', updateActiveDescendant);
81
+ }, [
82
+ updateActiveDescendant
83
+ ]);
84
+ // Make sure to memo so that React doesn't keep registering a new event listeners on every rerender of the wrapped collection
85
+ let mergedCollectionRef = (0, $4yz2I$reactariautils.useObjectRef)((0, $4yz2I$react.useMemo)(()=>(0, $4yz2I$reactariautils.mergeRefs)(collectionRef, callbackRef), [
86
+ collectionRef,
87
+ callbackRef
88
+ ]));
89
+ let focusFirstItem = (0, $4yz2I$reactariautils.useEffectEvent)(()=>{
90
+ var _collectionRef_current;
91
+ delayNextActiveDescendant.current = true;
92
+ (_collectionRef_current = collectionRef.current) === null || _collectionRef_current === void 0 ? void 0 : _collectionRef_current.dispatchEvent(new CustomEvent((0, $4yz2I$reactariautils.FOCUS_EVENT), {
93
+ cancelable: true,
94
+ bubbles: true,
95
+ detail: {
96
+ focusStrategy: 'first'
97
+ }
98
+ }));
99
+ });
100
+ let clearVirtualFocus = (0, $4yz2I$reactariautils.useEffectEvent)((clearFocusKey)=>{
101
+ var _collectionRef_current;
102
+ (0, $4yz2I$reactariafocus.moveVirtualFocus)((0, $4yz2I$reactariautils.getActiveElement)());
103
+ queuedActiveDescendant.current = null;
104
+ state.setFocusedNodeId(null);
105
+ let clearFocusEvent = new CustomEvent((0, $4yz2I$reactariautils.CLEAR_FOCUS_EVENT), {
106
+ cancelable: true,
107
+ bubbles: true,
108
+ detail: {
109
+ clearFocusKey: clearFocusKey
110
+ }
111
+ });
112
+ clearTimeout(timeout.current);
113
+ delayNextActiveDescendant.current = false;
114
+ (_collectionRef_current = collectionRef.current) === null || _collectionRef_current === void 0 ? void 0 : _collectionRef_current.dispatchEvent(clearFocusEvent);
115
+ });
116
+ // TODO: update to see if we can tell what kind of event (paste vs backspace vs typing) is happening instead
117
+ let onChange = (value)=>{
118
+ // Tell wrapped collection to focus the first element in the list when typing forward and to clear focused key when deleting text
119
+ // for screen reader announcements
120
+ if (state.inputValue !== value && state.inputValue.length <= value.length && !disableAutoFocusFirst) focusFirstItem();
121
+ else // Fully clear focused key when backspacing since the list may change and thus we'd want to start fresh again
122
+ clearVirtualFocus(true);
123
+ state.setInputValue(value);
124
+ };
125
+ let keyDownTarget = (0, $4yz2I$react.useRef)(null);
126
+ // For textfield specific keydown operations
127
+ let onKeyDown = (e)=>{
128
+ var _collectionRef_current;
129
+ keyDownTarget.current = e.target;
130
+ if (e.nativeEvent.isComposing) return;
131
+ let focusedNodeId = queuedActiveDescendant.current;
132
+ switch(e.key){
133
+ case 'a':
134
+ if ((0, $4yz2I$reactariautils.isCtrlKeyPressed)(e)) return;
135
+ break;
136
+ case 'Escape':
137
+ // Early return for Escape here so it doesn't leak the Escape event from the simulated collection event below and
138
+ // close the dialog prematurely. Ideally that should be up to the discretion of the input element hence the check
139
+ // for isPropagationStopped
140
+ if (e.isDefaultPrevented()) return;
141
+ break;
142
+ case ' ':
143
+ // Space shouldn't trigger onAction so early return.
144
+ return;
145
+ case 'Tab':
146
+ // Don't propogate Tab down to the collection, otherwise we will try to focus the collection via useSelectableCollection's Tab handler (aka shift tab logic)
147
+ // We want FocusScope to handle Tab if one exists (aka sub dialog), so special casepropogate
148
+ if ('continuePropagation' in e) e.continuePropagation();
149
+ return;
150
+ case 'Home':
151
+ case 'End':
152
+ case 'PageDown':
153
+ case 'PageUp':
154
+ case 'ArrowUp':
155
+ case 'ArrowDown':
156
+ {
157
+ var _collectionRef_current1;
158
+ if ((e.key === 'Home' || e.key === 'End') && focusedNodeId == null && e.shiftKey) return;
159
+ // Prevent these keys from moving the text cursor in the input
160
+ e.preventDefault();
161
+ // Move virtual focus into the wrapped collection
162
+ let focusCollection = new CustomEvent((0, $4yz2I$reactariautils.FOCUS_EVENT), {
163
+ cancelable: true,
164
+ bubbles: true
165
+ });
166
+ (_collectionRef_current1 = collectionRef.current) === null || _collectionRef_current1 === void 0 ? void 0 : _collectionRef_current1.dispatchEvent(focusCollection);
167
+ break;
168
+ }
169
+ }
170
+ // Emulate the keyboard events that happen in the input field in the wrapped collection. This is for triggering things like onAction via Enter
171
+ // or moving focus from one item to another. Stop propagation on the input event if it isn't already stopped so it doesn't leak out. For events
172
+ // like ESC, the dispatched event below will bubble out of the collection and be stopped if handled by useSelectableCollection, otherwise will bubble
173
+ // as expected
174
+ if (!e.isPropagationStopped()) e.stopPropagation();
175
+ let shouldPerformDefaultAction = true;
176
+ if (focusedNodeId == null) shouldPerformDefaultAction = ((_collectionRef_current = collectionRef.current) === null || _collectionRef_current === void 0 ? void 0 : _collectionRef_current.dispatchEvent(new KeyboardEvent(e.nativeEvent.type, e.nativeEvent))) || false;
177
+ else {
178
+ let item = document.getElementById(focusedNodeId);
179
+ shouldPerformDefaultAction = (item === null || item === void 0 ? void 0 : item.dispatchEvent(new KeyboardEvent(e.nativeEvent.type, e.nativeEvent))) || false;
180
+ }
181
+ if (shouldPerformDefaultAction) switch(e.key){
182
+ case 'ArrowLeft':
183
+ case 'ArrowRight':
184
+ // Clear the activedescendant so NVDA announcements aren't interrupted but retain the focused key in the collection so the
185
+ // user's keyboard navigation restarts from where they left off
186
+ clearVirtualFocus();
187
+ break;
188
+ }
189
+ };
190
+ let onKeyUpCapture = (0, $4yz2I$reactariautils.useEffectEvent)((e)=>{
191
+ // Dispatch simulated key up events for things like triggering links in listbox
192
+ // Make sure to stop the propagation of the input keyup event so that the simulated keyup/down pair
193
+ // is detected by usePress instead of the original keyup originating from the input
194
+ if (e.target === keyDownTarget.current) {
195
+ var _collectionRef_current;
196
+ e.stopImmediatePropagation();
197
+ let focusedNodeId = queuedActiveDescendant.current;
198
+ if (focusedNodeId == null) (_collectionRef_current = collectionRef.current) === null || _collectionRef_current === void 0 ? void 0 : _collectionRef_current.dispatchEvent(new KeyboardEvent(e.type, e));
199
+ else {
200
+ let item = document.getElementById(focusedNodeId);
201
+ item === null || item === void 0 ? void 0 : item.dispatchEvent(new KeyboardEvent(e.type, e));
202
+ }
203
+ }
204
+ });
205
+ (0, $4yz2I$react.useEffect)(()=>{
206
+ document.addEventListener('keyup', onKeyUpCapture, true);
207
+ return ()=>{
208
+ document.removeEventListener('keyup', onKeyUpCapture, true);
209
+ };
210
+ }, [
211
+ onKeyUpCapture
212
+ ]);
213
+ let stringFormatter = (0, $4yz2I$reactariai18n.useLocalizedStringFormatter)((0, ($parcel$interopDefault($fbc7b37667f52272$exports))), '@react-aria/autocomplete');
214
+ let collectionProps = (0, $4yz2I$reactariautils.useLabels)({
215
+ id: collectionId,
216
+ 'aria-label': stringFormatter.format('collectionLabel')
217
+ });
218
+ let filterFn = (0, $4yz2I$react.useCallback)((nodeTextValue)=>{
219
+ if (filter) return filter(nodeTextValue, state.inputValue);
220
+ return true;
221
+ }, [
222
+ state.inputValue,
223
+ filter
224
+ ]);
225
+ // Be sure to clear/restore the virtual + collection focus when blurring/refocusing the field so we only show the
226
+ // focus ring on the virtually focused collection when are actually interacting with the Autocomplete
227
+ let onBlur = (e)=>{
228
+ if (!e.isTrusted) return;
229
+ let lastFocusedNode = queuedActiveDescendant.current ? document.getElementById(queuedActiveDescendant.current) : null;
230
+ if (lastFocusedNode) (0, $4yz2I$reactariafocus.dispatchVirtualBlur)(lastFocusedNode, e.relatedTarget);
231
+ };
232
+ let onFocus = (e)=>{
233
+ if (!e.isTrusted) return;
234
+ let curFocusedNode = queuedActiveDescendant.current ? document.getElementById(queuedActiveDescendant.current) : null;
235
+ if (curFocusedNode) {
236
+ let target = e.target;
237
+ queueMicrotask(()=>{
238
+ (0, $4yz2I$reactariafocus.dispatchVirtualBlur)(target, curFocusedNode);
239
+ (0, $4yz2I$reactariafocus.dispatchVirtualFocus)(curFocusedNode, target);
240
+ });
241
+ }
242
+ };
243
+ var _state_focusedNodeId;
244
+ return {
245
+ textFieldProps: {
246
+ value: state.inputValue,
247
+ onChange: onChange,
248
+ onKeyDown: onKeyDown,
249
+ autoComplete: 'off',
250
+ 'aria-haspopup': 'listbox',
251
+ 'aria-controls': collectionId,
252
+ // TODO: readd proper logic for completionMode = complete (aria-autocomplete: both)
253
+ 'aria-autocomplete': 'list',
254
+ 'aria-activedescendant': (_state_focusedNodeId = state.focusedNodeId) !== null && _state_focusedNodeId !== void 0 ? _state_focusedNodeId : undefined,
255
+ // This disable's iOS's autocorrect suggestions, since the autocomplete provides its own suggestions.
256
+ autoCorrect: 'off',
257
+ // This disable's the macOS Safari spell check auto corrections.
258
+ spellCheck: 'false',
259
+ enterKeyHint: 'go',
260
+ onBlur: onBlur,
261
+ onFocus: onFocus
262
+ },
263
+ collectionProps: (0, $4yz2I$reactariautils.mergeProps)(collectionProps, {
264
+ shouldUseVirtualFocus: shouldUseVirtualFocus,
265
+ disallowTypeAhead: true
266
+ }),
267
+ collectionRef: mergedCollectionRef,
268
+ filter: filter != null ? filterFn : undefined
269
+ };
270
+ }
271
+
272
+
273
+ //# sourceMappingURL=useAutocomplete.main.js.map
@@ -0,0 +1 @@
1
+ {"mappings":"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","sources":["packages/@react-aria/autocomplete/src/useAutocomplete.ts"],"sourcesContent":["/*\n * Copyright 2024 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 permissions and limitations under the License.\n */\n\nimport {AriaLabelingProps, BaseEvent, DOMProps, RefObject} from '@react-types/shared';\nimport {AriaTextFieldProps} from '@react-aria/textfield';\nimport {AutocompleteProps, AutocompleteState} from '@react-stately/autocomplete';\nimport {CLEAR_FOCUS_EVENT, FOCUS_EVENT, getActiveElement, getOwnerDocument, isCtrlKeyPressed, mergeProps, mergeRefs, useEffectEvent, useId, useLabels, useObjectRef} from '@react-aria/utils';\nimport {dispatchVirtualBlur, dispatchVirtualFocus, moveVirtualFocus} from '@react-aria/focus';\nimport {getInteractionModality} from '@react-aria/interactions';\n// @ts-ignore\nimport intlMessages from '../intl/*.json';\nimport {FocusEvent as ReactFocusEvent, KeyboardEvent as ReactKeyboardEvent, useCallback, useEffect, useMemo, useRef} from 'react';\nimport {useLocalizedStringFormatter} from '@react-aria/i18n';\n\nexport interface CollectionOptions extends DOMProps, AriaLabelingProps {\n /** Whether the collection items should use virtual focus instead of being focused directly. */\n shouldUseVirtualFocus: boolean,\n /** Whether typeahead is disabled. */\n disallowTypeAhead: boolean\n}\nexport interface AriaAutocompleteProps extends AutocompleteProps {\n /**\n * An optional filter function used to determine if a option should be included in the autocomplete list.\n * Include this if the items you are providing to your wrapped collection aren't filtered by default.\n */\n filter?: (textValue: string, inputValue: string) => boolean,\n\n /**\n * Whether or not to focus the first item in the collection after a filter is performed.\n * @default false\n */\n disableAutoFocusFirst?: boolean\n}\n\nexport interface AriaAutocompleteOptions extends Omit<AriaAutocompleteProps, 'children'> {\n /** The ref for the wrapped collection element. */\n inputRef: RefObject<HTMLInputElement | null>,\n /** The ref for the wrapped collection element. */\n collectionRef: RefObject<HTMLElement | null>\n}\n\nexport interface AutocompleteAria {\n /** Props for the autocomplete textfield/searchfield element. These should be passed to the textfield/searchfield aria hooks respectively. */\n textFieldProps: AriaTextFieldProps,\n /** Props for the collection, to be passed to collection's respective aria hook (e.g. useMenu). */\n collectionProps: CollectionOptions,\n /** Ref to attach to the wrapped collection. */\n collectionRef: RefObject<HTMLElement | null>,\n /** A filter function that returns if the provided collection node should be filtered out of the collection. */\n filter?: (nodeTextValue: string) => boolean\n}\n\n/**\n * Provides the behavior and accessibility implementation for an autocomplete component.\n * An autocomplete combines a text input with a collection, allowing users to filter the collection's contents match a query.\n * @param props - Props for the autocomplete.\n * @param state - State for the autocomplete, as returned by `useAutocompleteState`.\n */\nexport function useAutocomplete(props: AriaAutocompleteOptions, state: AutocompleteState): AutocompleteAria {\n let {\n inputRef,\n collectionRef,\n filter,\n disableAutoFocusFirst = false\n } = props;\n\n let collectionId = useId();\n let timeout = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n let delayNextActiveDescendant = useRef(false);\n let queuedActiveDescendant = useRef<string | null>(null);\n let lastCollectionNode = useRef<HTMLElement>(null);\n\n // For mobile screen readers, we don't want virtual focus, instead opting to disable FocusScope's restoreFocus and manually\n // moving focus back to the subtriggers\n let shouldUseVirtualFocus = getInteractionModality() !== 'virtual';\n\n useEffect(() => {\n return () => clearTimeout(timeout.current);\n }, []);\n\n let updateActiveDescendant = useEffectEvent((e: Event) => {\n // Ensure input is focused if the user clicks on the collection directly.\n if (!e.isTrusted && shouldUseVirtualFocus && inputRef.current && getActiveElement(getOwnerDocument(inputRef.current)) !== inputRef.current) {\n inputRef.current.focus();\n }\n\n let target = e.target as Element | null;\n if (e.isTrusted || !target || queuedActiveDescendant.current === target.id) {\n return;\n }\n\n clearTimeout(timeout.current);\n if (target !== collectionRef.current) {\n if (delayNextActiveDescendant.current) {\n queuedActiveDescendant.current = target.id;\n timeout.current = setTimeout(() => {\n state.setFocusedNodeId(target.id);\n }, 500);\n } else {\n queuedActiveDescendant.current = target.id;\n state.setFocusedNodeId(target.id);\n }\n } else {\n queuedActiveDescendant.current = null;\n state.setFocusedNodeId(null);\n }\n\n delayNextActiveDescendant.current = false;\n });\n\n let callbackRef = useCallback((collectionNode) => {\n if (collectionNode != null) {\n // When typing forward, we want to delay the setting of active descendant to not interrupt the native screen reader announcement\n // of the letter you just typed. If we recieve another focus event then we clear the queued update\n // We track lastCollectionNode to do proper cleanup since callbackRefs just pass null when unmounting. This also handles\n // React 19's extra call of the callback ref in strict mode\n lastCollectionNode.current?.removeEventListener('focusin', updateActiveDescendant);\n lastCollectionNode.current = collectionNode;\n collectionNode.addEventListener('focusin', updateActiveDescendant);\n } else {\n lastCollectionNode.current?.removeEventListener('focusin', updateActiveDescendant);\n }\n }, [updateActiveDescendant]);\n\n // Make sure to memo so that React doesn't keep registering a new event listeners on every rerender of the wrapped collection\n let mergedCollectionRef = useObjectRef(useMemo(() => mergeRefs(collectionRef, callbackRef), [collectionRef, callbackRef]));\n\n let focusFirstItem = useEffectEvent(() => {\n delayNextActiveDescendant.current = true;\n collectionRef.current?.dispatchEvent(\n new CustomEvent(FOCUS_EVENT, {\n cancelable: true,\n bubbles: true,\n detail: {\n focusStrategy: 'first'\n }\n })\n );\n });\n\n let clearVirtualFocus = useEffectEvent((clearFocusKey?: boolean) => {\n moveVirtualFocus(getActiveElement());\n queuedActiveDescendant.current = null;\n state.setFocusedNodeId(null);\n let clearFocusEvent = new CustomEvent(CLEAR_FOCUS_EVENT, {\n cancelable: true,\n bubbles: true,\n detail: {\n clearFocusKey\n }\n });\n clearTimeout(timeout.current);\n delayNextActiveDescendant.current = false;\n collectionRef.current?.dispatchEvent(clearFocusEvent);\n });\n\n // TODO: update to see if we can tell what kind of event (paste vs backspace vs typing) is happening instead\n let onChange = (value: string) => {\n // Tell wrapped collection to focus the first element in the list when typing forward and to clear focused key when deleting text\n // for screen reader announcements\n if (state.inputValue !== value && state.inputValue.length <= value.length && !disableAutoFocusFirst) {\n focusFirstItem();\n } else {\n // Fully clear focused key when backspacing since the list may change and thus we'd want to start fresh again\n clearVirtualFocus(true);\n }\n\n state.setInputValue(value);\n };\n\n let keyDownTarget = useRef<Element | null>(null);\n // For textfield specific keydown operations\n let onKeyDown = (e: BaseEvent<ReactKeyboardEvent<any>>) => {\n keyDownTarget.current = e.target as Element;\n if (e.nativeEvent.isComposing) {\n return;\n }\n\n let focusedNodeId = queuedActiveDescendant.current;\n switch (e.key) {\n case 'a':\n if (isCtrlKeyPressed(e)) {\n return;\n }\n break;\n case 'Escape':\n // Early return for Escape here so it doesn't leak the Escape event from the simulated collection event below and\n // close the dialog prematurely. Ideally that should be up to the discretion of the input element hence the check\n // for isPropagationStopped\n if (e.isDefaultPrevented()) {\n return;\n }\n break;\n case ' ':\n // Space shouldn't trigger onAction so early return.\n return;\n case 'Tab':\n // Don't propogate Tab down to the collection, otherwise we will try to focus the collection via useSelectableCollection's Tab handler (aka shift tab logic)\n // We want FocusScope to handle Tab if one exists (aka sub dialog), so special casepropogate\n if ('continuePropagation' in e) {\n e.continuePropagation();\n }\n return;\n case 'Home':\n case 'End':\n case 'PageDown':\n case 'PageUp':\n case 'ArrowUp':\n case 'ArrowDown': {\n if ((e.key === 'Home' || e.key === 'End') && focusedNodeId == null && e.shiftKey) {\n return;\n }\n\n // Prevent these keys from moving the text cursor in the input\n e.preventDefault();\n // Move virtual focus into the wrapped collection\n let focusCollection = new CustomEvent(FOCUS_EVENT, {\n cancelable: true,\n bubbles: true\n });\n\n collectionRef.current?.dispatchEvent(focusCollection);\n break;\n }\n }\n\n // Emulate the keyboard events that happen in the input field in the wrapped collection. This is for triggering things like onAction via Enter\n // or moving focus from one item to another. Stop propagation on the input event if it isn't already stopped so it doesn't leak out. For events\n // like ESC, the dispatched event below will bubble out of the collection and be stopped if handled by useSelectableCollection, otherwise will bubble\n // as expected\n if (!e.isPropagationStopped()) {\n e.stopPropagation();\n }\n\n let shouldPerformDefaultAction = true;\n if (focusedNodeId == null) {\n shouldPerformDefaultAction = collectionRef.current?.dispatchEvent(\n new KeyboardEvent(e.nativeEvent.type, e.nativeEvent)\n ) || false;\n } else {\n let item = document.getElementById(focusedNodeId);\n shouldPerformDefaultAction = item?.dispatchEvent(\n new KeyboardEvent(e.nativeEvent.type, e.nativeEvent)\n ) || false;\n }\n\n if (shouldPerformDefaultAction) {\n switch (e.key) {\n case 'ArrowLeft':\n case 'ArrowRight': {\n // Clear the activedescendant so NVDA announcements aren't interrupted but retain the focused key in the collection so the\n // user's keyboard navigation restarts from where they left off\n clearVirtualFocus();\n break;\n }\n }\n }\n };\n\n let onKeyUpCapture = useEffectEvent((e) => {\n // Dispatch simulated key up events for things like triggering links in listbox\n // Make sure to stop the propagation of the input keyup event so that the simulated keyup/down pair\n // is detected by usePress instead of the original keyup originating from the input\n if (e.target === keyDownTarget.current) {\n e.stopImmediatePropagation();\n let focusedNodeId = queuedActiveDescendant.current;\n if (focusedNodeId == null) {\n collectionRef.current?.dispatchEvent(\n new KeyboardEvent(e.type, e)\n );\n } else {\n let item = document.getElementById(focusedNodeId);\n item?.dispatchEvent(\n new KeyboardEvent(e.type, e)\n );\n }\n }\n });\n\n useEffect(() => {\n document.addEventListener('keyup', onKeyUpCapture, true);\n return () => {\n document.removeEventListener('keyup', onKeyUpCapture, true);\n };\n }, [onKeyUpCapture]);\n\n let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-aria/autocomplete');\n let collectionProps = useLabels({\n id: collectionId,\n 'aria-label': stringFormatter.format('collectionLabel')\n });\n\n let filterFn = useCallback((nodeTextValue: string) => {\n if (filter) {\n return filter(nodeTextValue, state.inputValue);\n }\n\n return true;\n }, [state.inputValue, filter]);\n\n // Be sure to clear/restore the virtual + collection focus when blurring/refocusing the field so we only show the\n // focus ring on the virtually focused collection when are actually interacting with the Autocomplete\n let onBlur = (e: ReactFocusEvent) => {\n if (!e.isTrusted) {\n return;\n }\n\n let lastFocusedNode = queuedActiveDescendant.current ? document.getElementById(queuedActiveDescendant.current) : null;\n if (lastFocusedNode) {\n dispatchVirtualBlur(lastFocusedNode, e.relatedTarget);\n }\n };\n\n let onFocus = (e: ReactFocusEvent) => {\n if (!e.isTrusted) {\n return;\n }\n\n let curFocusedNode = queuedActiveDescendant.current ? document.getElementById(queuedActiveDescendant.current) : null;\n if (curFocusedNode) {\n let target = e.target;\n queueMicrotask(() => {\n dispatchVirtualBlur(target, curFocusedNode);\n dispatchVirtualFocus(curFocusedNode, target);\n });\n }\n };\n\n return {\n textFieldProps: {\n value: state.inputValue,\n onChange,\n onKeyDown,\n autoComplete: 'off',\n 'aria-haspopup': 'listbox',\n 'aria-controls': collectionId,\n // TODO: readd proper logic for completionMode = complete (aria-autocomplete: both)\n 'aria-autocomplete': 'list',\n 'aria-activedescendant': state.focusedNodeId ?? undefined,\n // This disable's iOS's autocorrect suggestions, since the autocomplete provides its own suggestions.\n autoCorrect: 'off',\n // This disable's the macOS Safari spell check auto corrections.\n spellCheck: 'false',\n enterKeyHint: 'go',\n onBlur,\n onFocus\n },\n collectionProps: mergeProps(collectionProps, {\n shouldUseVirtualFocus,\n disallowTypeAhead: true\n }),\n collectionRef: mergedCollectionRef,\n filter: filter != null ? filterFn : undefined\n };\n}\n"],"names":[],"version":3,"file":"useAutocomplete.main.js.map"}
@@ -0,0 +1,268 @@
1
+ import $4ELxY$intlStringsmodulejs from "./intlStrings.mjs";
2
+ import {useId as $4ELxY$useId, useEffectEvent as $4ELxY$useEffectEvent, getActiveElement as $4ELxY$getActiveElement, getOwnerDocument as $4ELxY$getOwnerDocument, useObjectRef as $4ELxY$useObjectRef, mergeRefs as $4ELxY$mergeRefs, FOCUS_EVENT as $4ELxY$FOCUS_EVENT, CLEAR_FOCUS_EVENT as $4ELxY$CLEAR_FOCUS_EVENT, isCtrlKeyPressed as $4ELxY$isCtrlKeyPressed, useLabels as $4ELxY$useLabels, mergeProps as $4ELxY$mergeProps} from "@react-aria/utils";
3
+ import {moveVirtualFocus as $4ELxY$moveVirtualFocus, dispatchVirtualBlur as $4ELxY$dispatchVirtualBlur, dispatchVirtualFocus as $4ELxY$dispatchVirtualFocus} from "@react-aria/focus";
4
+ import {getInteractionModality as $4ELxY$getInteractionModality} from "@react-aria/interactions";
5
+ import {useRef as $4ELxY$useRef, useEffect as $4ELxY$useEffect, useCallback as $4ELxY$useCallback, useMemo as $4ELxY$useMemo} from "react";
6
+ import {useLocalizedStringFormatter as $4ELxY$useLocalizedStringFormatter} from "@react-aria/i18n";
7
+
8
+
9
+ function $parcel$interopDefault(a) {
10
+ return a && a.__esModule ? a.default : a;
11
+ }
12
+ /*
13
+ * Copyright 2024 Adobe. All rights reserved.
14
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
15
+ * you may not use this file except in compliance with the License. You may obtain a copy
16
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
17
+ *
18
+ * Unless required by applicable law or agreed to in writing, software distributed under
19
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
20
+ * OF ANY KIND, either express or implied. See the License for the specific language
21
+ * governing permissions and limitations under the License.
22
+ */
23
+
24
+
25
+
26
+
27
+
28
+ function $48f6ba390f8c5b59$export$1e40b3ca02d92d21(props, state) {
29
+ let { inputRef: inputRef, collectionRef: collectionRef, filter: filter, disableAutoFocusFirst: disableAutoFocusFirst = false } = props;
30
+ let collectionId = (0, $4ELxY$useId)();
31
+ let timeout = (0, $4ELxY$useRef)(undefined);
32
+ let delayNextActiveDescendant = (0, $4ELxY$useRef)(false);
33
+ let queuedActiveDescendant = (0, $4ELxY$useRef)(null);
34
+ let lastCollectionNode = (0, $4ELxY$useRef)(null);
35
+ // For mobile screen readers, we don't want virtual focus, instead opting to disable FocusScope's restoreFocus and manually
36
+ // moving focus back to the subtriggers
37
+ let shouldUseVirtualFocus = (0, $4ELxY$getInteractionModality)() !== 'virtual';
38
+ (0, $4ELxY$useEffect)(()=>{
39
+ return ()=>clearTimeout(timeout.current);
40
+ }, []);
41
+ let updateActiveDescendant = (0, $4ELxY$useEffectEvent)((e)=>{
42
+ // Ensure input is focused if the user clicks on the collection directly.
43
+ if (!e.isTrusted && shouldUseVirtualFocus && inputRef.current && (0, $4ELxY$getActiveElement)((0, $4ELxY$getOwnerDocument)(inputRef.current)) !== inputRef.current) inputRef.current.focus();
44
+ let target = e.target;
45
+ if (e.isTrusted || !target || queuedActiveDescendant.current === target.id) return;
46
+ clearTimeout(timeout.current);
47
+ if (target !== collectionRef.current) {
48
+ if (delayNextActiveDescendant.current) {
49
+ queuedActiveDescendant.current = target.id;
50
+ timeout.current = setTimeout(()=>{
51
+ state.setFocusedNodeId(target.id);
52
+ }, 500);
53
+ } else {
54
+ queuedActiveDescendant.current = target.id;
55
+ state.setFocusedNodeId(target.id);
56
+ }
57
+ } else {
58
+ queuedActiveDescendant.current = null;
59
+ state.setFocusedNodeId(null);
60
+ }
61
+ delayNextActiveDescendant.current = false;
62
+ });
63
+ let callbackRef = (0, $4ELxY$useCallback)((collectionNode)=>{
64
+ var _lastCollectionNode_current;
65
+ if (collectionNode != null) {
66
+ var // When typing forward, we want to delay the setting of active descendant to not interrupt the native screen reader announcement
67
+ // of the letter you just typed. If we recieve another focus event then we clear the queued update
68
+ // We track lastCollectionNode to do proper cleanup since callbackRefs just pass null when unmounting. This also handles
69
+ // React 19's extra call of the callback ref in strict mode
70
+ _lastCollectionNode_current1;
71
+ (_lastCollectionNode_current1 = lastCollectionNode.current) === null || _lastCollectionNode_current1 === void 0 ? void 0 : _lastCollectionNode_current1.removeEventListener('focusin', updateActiveDescendant);
72
+ lastCollectionNode.current = collectionNode;
73
+ collectionNode.addEventListener('focusin', updateActiveDescendant);
74
+ } else (_lastCollectionNode_current = lastCollectionNode.current) === null || _lastCollectionNode_current === void 0 ? void 0 : _lastCollectionNode_current.removeEventListener('focusin', updateActiveDescendant);
75
+ }, [
76
+ updateActiveDescendant
77
+ ]);
78
+ // Make sure to memo so that React doesn't keep registering a new event listeners on every rerender of the wrapped collection
79
+ let mergedCollectionRef = (0, $4ELxY$useObjectRef)((0, $4ELxY$useMemo)(()=>(0, $4ELxY$mergeRefs)(collectionRef, callbackRef), [
80
+ collectionRef,
81
+ callbackRef
82
+ ]));
83
+ let focusFirstItem = (0, $4ELxY$useEffectEvent)(()=>{
84
+ var _collectionRef_current;
85
+ delayNextActiveDescendant.current = true;
86
+ (_collectionRef_current = collectionRef.current) === null || _collectionRef_current === void 0 ? void 0 : _collectionRef_current.dispatchEvent(new CustomEvent((0, $4ELxY$FOCUS_EVENT), {
87
+ cancelable: true,
88
+ bubbles: true,
89
+ detail: {
90
+ focusStrategy: 'first'
91
+ }
92
+ }));
93
+ });
94
+ let clearVirtualFocus = (0, $4ELxY$useEffectEvent)((clearFocusKey)=>{
95
+ var _collectionRef_current;
96
+ (0, $4ELxY$moveVirtualFocus)((0, $4ELxY$getActiveElement)());
97
+ queuedActiveDescendant.current = null;
98
+ state.setFocusedNodeId(null);
99
+ let clearFocusEvent = new CustomEvent((0, $4ELxY$CLEAR_FOCUS_EVENT), {
100
+ cancelable: true,
101
+ bubbles: true,
102
+ detail: {
103
+ clearFocusKey: clearFocusKey
104
+ }
105
+ });
106
+ clearTimeout(timeout.current);
107
+ delayNextActiveDescendant.current = false;
108
+ (_collectionRef_current = collectionRef.current) === null || _collectionRef_current === void 0 ? void 0 : _collectionRef_current.dispatchEvent(clearFocusEvent);
109
+ });
110
+ // TODO: update to see if we can tell what kind of event (paste vs backspace vs typing) is happening instead
111
+ let onChange = (value)=>{
112
+ // Tell wrapped collection to focus the first element in the list when typing forward and to clear focused key when deleting text
113
+ // for screen reader announcements
114
+ if (state.inputValue !== value && state.inputValue.length <= value.length && !disableAutoFocusFirst) focusFirstItem();
115
+ else // Fully clear focused key when backspacing since the list may change and thus we'd want to start fresh again
116
+ clearVirtualFocus(true);
117
+ state.setInputValue(value);
118
+ };
119
+ let keyDownTarget = (0, $4ELxY$useRef)(null);
120
+ // For textfield specific keydown operations
121
+ let onKeyDown = (e)=>{
122
+ var _collectionRef_current;
123
+ keyDownTarget.current = e.target;
124
+ if (e.nativeEvent.isComposing) return;
125
+ let focusedNodeId = queuedActiveDescendant.current;
126
+ switch(e.key){
127
+ case 'a':
128
+ if ((0, $4ELxY$isCtrlKeyPressed)(e)) return;
129
+ break;
130
+ case 'Escape':
131
+ // Early return for Escape here so it doesn't leak the Escape event from the simulated collection event below and
132
+ // close the dialog prematurely. Ideally that should be up to the discretion of the input element hence the check
133
+ // for isPropagationStopped
134
+ if (e.isDefaultPrevented()) return;
135
+ break;
136
+ case ' ':
137
+ // Space shouldn't trigger onAction so early return.
138
+ return;
139
+ case 'Tab':
140
+ // Don't propogate Tab down to the collection, otherwise we will try to focus the collection via useSelectableCollection's Tab handler (aka shift tab logic)
141
+ // We want FocusScope to handle Tab if one exists (aka sub dialog), so special casepropogate
142
+ if ('continuePropagation' in e) e.continuePropagation();
143
+ return;
144
+ case 'Home':
145
+ case 'End':
146
+ case 'PageDown':
147
+ case 'PageUp':
148
+ case 'ArrowUp':
149
+ case 'ArrowDown':
150
+ {
151
+ var _collectionRef_current1;
152
+ if ((e.key === 'Home' || e.key === 'End') && focusedNodeId == null && e.shiftKey) return;
153
+ // Prevent these keys from moving the text cursor in the input
154
+ e.preventDefault();
155
+ // Move virtual focus into the wrapped collection
156
+ let focusCollection = new CustomEvent((0, $4ELxY$FOCUS_EVENT), {
157
+ cancelable: true,
158
+ bubbles: true
159
+ });
160
+ (_collectionRef_current1 = collectionRef.current) === null || _collectionRef_current1 === void 0 ? void 0 : _collectionRef_current1.dispatchEvent(focusCollection);
161
+ break;
162
+ }
163
+ }
164
+ // Emulate the keyboard events that happen in the input field in the wrapped collection. This is for triggering things like onAction via Enter
165
+ // or moving focus from one item to another. Stop propagation on the input event if it isn't already stopped so it doesn't leak out. For events
166
+ // like ESC, the dispatched event below will bubble out of the collection and be stopped if handled by useSelectableCollection, otherwise will bubble
167
+ // as expected
168
+ if (!e.isPropagationStopped()) e.stopPropagation();
169
+ let shouldPerformDefaultAction = true;
170
+ if (focusedNodeId == null) shouldPerformDefaultAction = ((_collectionRef_current = collectionRef.current) === null || _collectionRef_current === void 0 ? void 0 : _collectionRef_current.dispatchEvent(new KeyboardEvent(e.nativeEvent.type, e.nativeEvent))) || false;
171
+ else {
172
+ let item = document.getElementById(focusedNodeId);
173
+ shouldPerformDefaultAction = (item === null || item === void 0 ? void 0 : item.dispatchEvent(new KeyboardEvent(e.nativeEvent.type, e.nativeEvent))) || false;
174
+ }
175
+ if (shouldPerformDefaultAction) switch(e.key){
176
+ case 'ArrowLeft':
177
+ case 'ArrowRight':
178
+ // Clear the activedescendant so NVDA announcements aren't interrupted but retain the focused key in the collection so the
179
+ // user's keyboard navigation restarts from where they left off
180
+ clearVirtualFocus();
181
+ break;
182
+ }
183
+ };
184
+ let onKeyUpCapture = (0, $4ELxY$useEffectEvent)((e)=>{
185
+ // Dispatch simulated key up events for things like triggering links in listbox
186
+ // Make sure to stop the propagation of the input keyup event so that the simulated keyup/down pair
187
+ // is detected by usePress instead of the original keyup originating from the input
188
+ if (e.target === keyDownTarget.current) {
189
+ var _collectionRef_current;
190
+ e.stopImmediatePropagation();
191
+ let focusedNodeId = queuedActiveDescendant.current;
192
+ if (focusedNodeId == null) (_collectionRef_current = collectionRef.current) === null || _collectionRef_current === void 0 ? void 0 : _collectionRef_current.dispatchEvent(new KeyboardEvent(e.type, e));
193
+ else {
194
+ let item = document.getElementById(focusedNodeId);
195
+ item === null || item === void 0 ? void 0 : item.dispatchEvent(new KeyboardEvent(e.type, e));
196
+ }
197
+ }
198
+ });
199
+ (0, $4ELxY$useEffect)(()=>{
200
+ document.addEventListener('keyup', onKeyUpCapture, true);
201
+ return ()=>{
202
+ document.removeEventListener('keyup', onKeyUpCapture, true);
203
+ };
204
+ }, [
205
+ onKeyUpCapture
206
+ ]);
207
+ let stringFormatter = (0, $4ELxY$useLocalizedStringFormatter)((0, ($parcel$interopDefault($4ELxY$intlStringsmodulejs))), '@react-aria/autocomplete');
208
+ let collectionProps = (0, $4ELxY$useLabels)({
209
+ id: collectionId,
210
+ 'aria-label': stringFormatter.format('collectionLabel')
211
+ });
212
+ let filterFn = (0, $4ELxY$useCallback)((nodeTextValue)=>{
213
+ if (filter) return filter(nodeTextValue, state.inputValue);
214
+ return true;
215
+ }, [
216
+ state.inputValue,
217
+ filter
218
+ ]);
219
+ // Be sure to clear/restore the virtual + collection focus when blurring/refocusing the field so we only show the
220
+ // focus ring on the virtually focused collection when are actually interacting with the Autocomplete
221
+ let onBlur = (e)=>{
222
+ if (!e.isTrusted) return;
223
+ let lastFocusedNode = queuedActiveDescendant.current ? document.getElementById(queuedActiveDescendant.current) : null;
224
+ if (lastFocusedNode) (0, $4ELxY$dispatchVirtualBlur)(lastFocusedNode, e.relatedTarget);
225
+ };
226
+ let onFocus = (e)=>{
227
+ if (!e.isTrusted) return;
228
+ let curFocusedNode = queuedActiveDescendant.current ? document.getElementById(queuedActiveDescendant.current) : null;
229
+ if (curFocusedNode) {
230
+ let target = e.target;
231
+ queueMicrotask(()=>{
232
+ (0, $4ELxY$dispatchVirtualBlur)(target, curFocusedNode);
233
+ (0, $4ELxY$dispatchVirtualFocus)(curFocusedNode, target);
234
+ });
235
+ }
236
+ };
237
+ var _state_focusedNodeId;
238
+ return {
239
+ textFieldProps: {
240
+ value: state.inputValue,
241
+ onChange: onChange,
242
+ onKeyDown: onKeyDown,
243
+ autoComplete: 'off',
244
+ 'aria-haspopup': 'listbox',
245
+ 'aria-controls': collectionId,
246
+ // TODO: readd proper logic for completionMode = complete (aria-autocomplete: both)
247
+ 'aria-autocomplete': 'list',
248
+ 'aria-activedescendant': (_state_focusedNodeId = state.focusedNodeId) !== null && _state_focusedNodeId !== void 0 ? _state_focusedNodeId : undefined,
249
+ // This disable's iOS's autocorrect suggestions, since the autocomplete provides its own suggestions.
250
+ autoCorrect: 'off',
251
+ // This disable's the macOS Safari spell check auto corrections.
252
+ spellCheck: 'false',
253
+ enterKeyHint: 'go',
254
+ onBlur: onBlur,
255
+ onFocus: onFocus
256
+ },
257
+ collectionProps: (0, $4ELxY$mergeProps)(collectionProps, {
258
+ shouldUseVirtualFocus: shouldUseVirtualFocus,
259
+ disallowTypeAhead: true
260
+ }),
261
+ collectionRef: mergedCollectionRef,
262
+ filter: filter != null ? filterFn : undefined
263
+ };
264
+ }
265
+
266
+
267
+ export {$48f6ba390f8c5b59$export$1e40b3ca02d92d21 as useAutocomplete};
268
+ //# sourceMappingURL=useAutocomplete.module.js.map