@react-aria/autocomplete 3.0.0-rc.2 → 3.0.0-rc.3

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.
@@ -1 +1 @@
1
- {"mappings":";;;;;;;;AAsBA,wCAAwC,CAAC,CAAE,SAAQ,gBAAgB;IACjE,mCAAmC;IACnC,UAAU,EAAE,aAAa,CAAC;IAC1B,0CAA0C;IAC1C,UAAU,EAAE,oBAAoB,gBAAgB,CAAC,CAAC;IAClD,6EAA6E;IAC7E,YAAY,EAAE,mBAAmB,CAAC,CAAC,CAAC;IACpC,iDAAiD;IACjD,gBAAgB,EAAE,eAAe,CAAC;IAClC,qEAAqE;IACrE,gBAAgB,EAAE,aAAa,CAAC;IAChC,uEAAuE;IACvE,iBAAiB,EAAE,aAAa,CAAA;CACjC;AAED,+CAA+C,CAAC,CAAE,SAAQ,4BAA4B,CAAC,CAAC;IACtF,qCAAqC;IACrC,QAAQ,EAAE,UAAU,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAC7C,wCAAwC;IACxC,UAAU,EAAE,UAAU,cAAc,GAAG,IAAI,CAAC,CAAC;IAC7C,gCAAgC;IAChC,UAAU,EAAE,UAAU,WAAW,GAAG,IAAI,CAAC,CAAC;IAC1C,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC;;;;OAIG;IACH,cAAc,CAAC,EAAE,cAAc,CAAA;CAChC;AAED;;;;;GAKG;AACH,sCAAsC,CAAC,EAAE,KAAK,EAAE,8BAA8B,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,GAAG,uBAAuB,CAAC,CAAC,CAwEpI;AC7GD,kCAAmC,SAAQ,QAAQ,EAAE,iBAAiB;IACpE,+FAA+F;IAC/F,qBAAqB,EAAE,OAAO,CAAC;IAC/B,qCAAqC;IACrC,iBAAiB,EAAE,OAAO,CAAA;CAC3B;AAED,4BAA4B,CAAC,GAAG,gBAAgB,CAAE,SAAQ,QAAQ,EAChE,YAAY,CAAC,CAAC,EACd,cAAc,EACd,IAAI,CAAC,UAAU,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,EAC7C,IAAI,CAAC,kBAAkB,EAAE,cAAc,GAAG,eAAe,GAAG,mBAAmB,GAAG,uBAAuB,GAAG,YAAY,GAAG,aAAa,GAAG,cAAc,CAAC;CAAG;AAE/J,uCAAuC,CAAC,CAAE,SAAQ,iBAAiB;IACjE;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,KAAK,OAAO,CAAC;IAE3E;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAEhC;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAC9B;AAED,yCAAyC,CAAC,CAAE,SAAQ,IAAI,CAAC,sBAAsB,CAAC,CAAC,EAAE,UAAU,CAAC;IAC5F,kDAAkD;IAClD,QAAQ,EAAE,UAAU,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAC7C,kDAAkD;IAClD,aAAa,EAAE,UAAU,WAAW,GAAG,IAAI,CAAC,CAAA;CAC7C;AAED,kCAAkC,CAAC;IACjC,sJAAsJ;IACtJ,UAAU,EAAE,UAAU,CAAC;IACvB,kGAAkG;IAClG,eAAe,EAAE,iBAAiB,CAAC;IACnC,+CAA+C;IAC/C,aAAa,EAAE,UAAU,WAAW,GAAG,IAAI,CAAC,CAAC;IAC7C,+GAA+G;IAC/G,MAAM,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,KAAK,OAAO,CAAA;CAC3D;AAED;;;;;GAKG;AACH,gCAAgC,CAAC,EAAE,KAAK,EAAE,wBAAwB,CAAC,CAAC,EAAE,KAAK,EAAE,iBAAiB,GAAG,iBAAiB,CAAC,CAAC,CAmVnH;ACrZD,YAAY,EAAC,2BAA2B,EAAC,MAAM,2BAA2B,CAAC","sources":["packages/@react-aria/autocomplete/src/packages/@react-aria/autocomplete/src/useSearchAutocomplete.ts","packages/@react-aria/autocomplete/src/packages/@react-aria/autocomplete/src/useAutocomplete.ts","packages/@react-aria/autocomplete/src/packages/@react-aria/autocomplete/src/index.ts","packages/@react-aria/autocomplete/src/index.ts"],"sourcesContent":[null,null,null,"/*\n * Copyright 2021 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 */\nexport {useSearchAutocomplete} from './useSearchAutocomplete';\nexport {useAutocomplete} from './useAutocomplete';\n\nexport type {AriaSearchAutocompleteOptions, SearchAutocompleteAria} from './useSearchAutocomplete';\nexport type {AriaSearchAutocompleteProps} from '@react-types/autocomplete';\nexport type {AriaAutocompleteProps, AriaAutocompleteOptions, AutocompleteAria, CollectionOptions, InputProps} from './useAutocomplete';\n"],"names":[],"version":3,"file":"types.d.ts.map"}
1
+ {"mappings":";;;;;;;;AAsBA,wCAAwC,CAAC,CAAE,SAAQ,gBAAgB;IACjE,mCAAmC;IACnC,UAAU,EAAE,aAAa,CAAC;IAC1B,0CAA0C;IAC1C,UAAU,EAAE,oBAAoB,gBAAgB,CAAC,CAAC;IAClD,6EAA6E;IAC7E,YAAY,EAAE,mBAAmB,CAAC,CAAC,CAAC;IACpC,iDAAiD;IACjD,gBAAgB,EAAE,eAAe,CAAC;IAClC,qEAAqE;IACrE,gBAAgB,EAAE,aAAa,CAAC;IAChC,uEAAuE;IACvE,iBAAiB,EAAE,aAAa,CAAA;CACjC;AAED,+CAA+C,CAAC,CAAE,SAAQ,4BAA4B,CAAC,CAAC;IACtF,qCAAqC;IACrC,QAAQ,EAAE,UAAU,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAC7C,wCAAwC;IACxC,UAAU,EAAE,UAAU,cAAc,GAAG,IAAI,CAAC,CAAC;IAC7C,gCAAgC;IAChC,UAAU,EAAE,UAAU,WAAW,GAAG,IAAI,CAAC,CAAC;IAC1C,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC;;;;OAIG;IACH,cAAc,CAAC,EAAE,cAAc,CAAA;CAChC;AAED;;;;;GAKG;AACH,sCAAsC,CAAC,EAAE,KAAK,EAAE,8BAA8B,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,GAAG,uBAAuB,CAAC,CAAC,CAwEpI;AC7GD,kCAAmC,SAAQ,QAAQ,EAAE,iBAAiB;IACpE,+FAA+F;IAC/F,qBAAqB,EAAE,OAAO,CAAC;IAC/B,qCAAqC;IACrC,iBAAiB,EAAE,OAAO,CAAA;CAC3B;AAED,4BAA4B,CAAC,GAAG,gBAAgB,CAAE,SAAQ,QAAQ,EAChE,YAAY,CAAC,CAAC,EACd,cAAc,EACd,IAAI,CAAC,UAAU,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,EAC7C,IAAI,CAAC,kBAAkB,EAAE,cAAc,GAAG,eAAe,GAAG,mBAAmB,GAAG,uBAAuB,GAAG,YAAY,GAAG,aAAa,GAAG,cAAc,CAAC;CAAG;AAE/J,uCAAuC,CAAC,CAAE,SAAQ,iBAAiB;IACjE;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,KAAK,OAAO,CAAC;IAE3E;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAEhC;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAC9B;AAED,yCAAyC,CAAC,CAAE,SAAQ,IAAI,CAAC,sBAAsB,CAAC,CAAC,EAAE,UAAU,CAAC;IAC5F,kDAAkD;IAClD,QAAQ,EAAE,UAAU,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAC7C,kDAAkD;IAClD,aAAa,EAAE,UAAU,WAAW,GAAG,IAAI,CAAC,CAAA;CAC7C;AAED,kCAAkC,CAAC;IACjC,sJAAsJ;IACtJ,UAAU,EAAE,UAAU,CAAC;IACvB,kGAAkG;IAClG,eAAe,EAAE,iBAAiB,CAAC;IACnC,+CAA+C;IAC/C,aAAa,EAAE,UAAU,WAAW,GAAG,IAAI,CAAC,CAAC;IAC7C,+GAA+G;IAC/G,MAAM,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,KAAK,OAAO,CAAA;CAC3D;AAED;;;;;GAKG;AACH,gCAAgC,CAAC,EAAE,KAAK,EAAE,wBAAwB,CAAC,CAAC,EAAE,KAAK,EAAE,iBAAiB,GAAG,iBAAiB,CAAC,CAAC,CA+VnH;ACjaD,YAAY,EAAC,2BAA2B,EAAC,MAAM,2BAA2B,CAAC","sources":["packages/@react-aria/autocomplete/src/packages/@react-aria/autocomplete/src/useSearchAutocomplete.ts","packages/@react-aria/autocomplete/src/packages/@react-aria/autocomplete/src/useAutocomplete.ts","packages/@react-aria/autocomplete/src/packages/@react-aria/autocomplete/src/index.ts","packages/@react-aria/autocomplete/src/index.ts"],"sourcesContent":[null,null,null,"/*\n * Copyright 2021 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 */\nexport {useSearchAutocomplete} from './useSearchAutocomplete';\nexport {useAutocomplete} from './useAutocomplete';\n\nexport type {AriaSearchAutocompleteOptions, SearchAutocompleteAria} from './useSearchAutocomplete';\nexport type {AriaSearchAutocompleteProps} from '@react-types/autocomplete';\nexport type {AriaAutocompleteProps, AriaAutocompleteOptions, AutocompleteAria, CollectionOptions, InputProps} from './useAutocomplete';\n"],"names":[],"version":3,"file":"types.d.ts.map"}
@@ -33,7 +33,7 @@ $parcel$export(module.exports, "useAutocomplete", () => $d43aec1bf2be84e8$export
33
33
 
34
34
  function $d43aec1bf2be84e8$export$1e40b3ca02d92d21(props, state) {
35
35
  let { inputRef: inputRef, collectionRef: collectionRef, filter: filter, disableAutoFocusFirst: disableAutoFocusFirst = false, disableVirtualFocus: disableVirtualFocus = false } = props;
36
- let collectionId = (0, $4yz2I$reactariautils.useSlotId)();
36
+ let collectionId = (0, $4yz2I$reactariautils.useId)();
37
37
  let timeout = (0, $4yz2I$react.useRef)(undefined);
38
38
  let delayNextActiveDescendant = (0, $4yz2I$react.useRef)(false);
39
39
  let queuedActiveDescendant = (0, $4yz2I$react.useRef)(null);
@@ -41,7 +41,10 @@ function $d43aec1bf2be84e8$export$1e40b3ca02d92d21(props, state) {
41
41
  // For mobile screen readers, we don't want virtual focus, instead opting to disable FocusScope's restoreFocus and manually
42
42
  // moving focus back to the subtriggers
43
43
  let isMobileScreenReader = (0, $4yz2I$reactariainteractions.getInteractionModality)() === 'virtual' && ((0, $4yz2I$reactariautils.isIOS)() || (0, $4yz2I$reactariautils.isAndroid)());
44
- let shouldUseVirtualFocus = !isMobileScreenReader && !disableVirtualFocus;
44
+ let [shouldUseVirtualFocus, setShouldUseVirtualFocus] = (0, $4yz2I$react.useState)(!isMobileScreenReader && !disableVirtualFocus);
45
+ // Tracks if a collection has been connected to the autocomplete. If false, we don't want to add various attributes to the autocomplete input
46
+ // since it isn't attached to a filterable collection (e.g. Tabs)
47
+ let [hasCollection, setHasCollection] = (0, $4yz2I$react.useState)(false);
45
48
  (0, $4yz2I$react.useEffect)(()=>{
46
49
  return ()=>clearTimeout(timeout.current);
47
50
  }, []);
@@ -72,17 +75,25 @@ function $d43aec1bf2be84e8$export$1e40b3ca02d92d21(props, state) {
72
75
  delayNextActiveDescendant.current = false;
73
76
  });
74
77
  let callbackRef = (0, $4yz2I$react.useCallback)((collectionNode)=>{
75
- var _lastCollectionNode_current;
76
78
  if (collectionNode != null) {
77
79
  var // When typing forward, we want to delay the setting of active descendant to not interrupt the native screen reader announcement
78
80
  // of the letter you just typed. If we recieve another focus event then we clear the queued update
79
81
  // We track lastCollectionNode to do proper cleanup since callbackRefs just pass null when unmounting. This also handles
80
82
  // React 19's extra call of the callback ref in strict mode
81
- _lastCollectionNode_current1;
82
- (_lastCollectionNode_current1 = lastCollectionNode.current) === null || _lastCollectionNode_current1 === void 0 ? void 0 : _lastCollectionNode_current1.removeEventListener('focusin', updateActiveDescendant);
83
+ _lastCollectionNode_current;
84
+ (_lastCollectionNode_current = lastCollectionNode.current) === null || _lastCollectionNode_current === void 0 ? void 0 : _lastCollectionNode_current.removeEventListener('focusin', updateActiveDescendant);
83
85
  lastCollectionNode.current = collectionNode;
84
86
  collectionNode.addEventListener('focusin', updateActiveDescendant);
85
- } else (_lastCollectionNode_current = lastCollectionNode.current) === null || _lastCollectionNode_current === void 0 ? void 0 : _lastCollectionNode_current.removeEventListener('focusin', updateActiveDescendant);
87
+ // If useSelectableCollection isn't passed shouldUseVirtualFocus even when useAutocomplete provides it
88
+ // that means the collection doesn't support it (e.g. Table). If that is the case, we need to disable it here regardless
89
+ // of what the user's provided so that the input doesn't recieve the onKeyDown and autocomplete props.
90
+ if (collectionNode.getAttribute('tabindex') != null) setShouldUseVirtualFocus(false);
91
+ setHasCollection(true);
92
+ } else {
93
+ var _lastCollectionNode_current1;
94
+ (_lastCollectionNode_current1 = lastCollectionNode.current) === null || _lastCollectionNode_current1 === void 0 ? void 0 : _lastCollectionNode_current1.removeEventListener('focusin', updateActiveDescendant);
95
+ setHasCollection(false);
96
+ }
86
97
  }, [
87
98
  updateActiveDescendant
88
99
  ]);
@@ -278,7 +289,7 @@ function $d43aec1bf2be84e8$export$1e40b3ca02d92d21(props, state) {
278
289
  onBlur: onBlur,
279
290
  onFocus: onFocus
280
291
  };
281
- if (collectionId) inputProps = {
292
+ if (hasCollection) inputProps = {
282
293
  ...inputProps,
283
294
  ...shouldUseVirtualFocus && virtualFocusProps,
284
295
  enterKeyHint: 'go',
@@ -295,7 +306,7 @@ function $d43aec1bf2be84e8$export$1e40b3ca02d92d21(props, state) {
295
306
  inputProps: inputProps,
296
307
  collectionProps: (0, $4yz2I$reactariautils.mergeProps)(collectionProps, {
297
308
  shouldUseVirtualFocus: shouldUseVirtualFocus,
298
- disallowTypeAhead: true
309
+ disallowTypeAhead: shouldUseVirtualFocus
299
310
  }),
300
311
  collectionRef: mergedCollectionRef,
301
312
  filter: filter != null ? filterFn : undefined
@@ -1 +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, FocusableElement, FocusEvents, KeyboardEvents, Node, RefObject, ValueBase} 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, isAndroid, isCtrlKeyPressed, isIOS, mergeProps, mergeRefs, useEffectEvent, useEvent, useLabels, useObjectRef, useSlotId} from '@react-aria/utils';\nimport {dispatchVirtualBlur, dispatchVirtualFocus, getVirtuallyFocusedElement, 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}\n\nexport interface InputProps<T = FocusableElement> extends DOMProps,\n FocusEvents<T>,\n KeyboardEvents,\n Pick<ValueBase<string>, 'onChange' | 'value'>,\n Pick<AriaTextFieldProps, 'enterKeyHint' | 'aria-controls' | 'aria-autocomplete' | 'aria-activedescendant' | 'spellCheck' | 'autoCorrect' | 'autoComplete'> {}\n\nexport interface AriaAutocompleteProps<T> 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, node: Node<T>) => boolean,\n\n /**\n * Whether or not to focus the first item in the collection after a filter is performed. Note this is only applicable\n * if virtual focus behavior is not turned off via `disableVirtualFocus`.\n * @default false\n */\n disableAutoFocusFirst?: boolean,\n\n /**\n * Whether the autocomplete should disable virtual focus, instead making the wrapped collection directly tabbable.\n * @default false\n */\n disableVirtualFocus?: boolean\n}\n\nexport interface AriaAutocompleteOptions<T> extends Omit<AriaAutocompleteProps<T>, '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<T> {\n /** Props for the autocomplete input element. These should be passed to the input's aria hooks (e.g. useTextField/useSearchField/etc) respectively. */\n inputProps: InputProps,\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, node: Node<T>) => 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<T>(props: AriaAutocompleteOptions<T>, state: AutocompleteState): AutocompleteAria<T> {\n let {\n inputRef,\n collectionRef,\n filter,\n disableAutoFocusFirst = false,\n disableVirtualFocus = false\n } = props;\n\n let collectionId = useSlotId();\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 isMobileScreenReader = getInteractionModality() === 'virtual' && (isIOS() || isAndroid());\n let shouldUseVirtualFocus = !isMobileScreenReader && !disableVirtualFocus;\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 if (queuedActiveDescendant.current && !document.getElementById(queuedActiveDescendant.current)) {\n // If we recieve a focus event refocusing the collection, either we have newly refocused the input and are waiting for the\n // wrapped collection to refocus the previously focused node if any OR\n // we are in a state where we've filtered to such a point that there aren't any matching items in the collection to focus.\n // In this case we want to clear tracked item if any and clear active descendant\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 let lastInputType = useRef('');\n useEvent(inputRef, 'input', e => {\n let {inputType} = e as InputEvent;\n lastInputType.current = inputType;\n });\n\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 modifying the text via\n // copy paste/backspacing/undo/redo for screen reader announcements\n if (lastInputType.current === 'insertText' && !disableAutoFocusFirst) {\n focusFirstItem();\n } else if (lastInputType.current && (lastInputType.current.includes('insert') || lastInputType.current.includes('delete') || lastInputType.current.includes('history'))) {\n clearVirtualFocus(true);\n\n // If onChange was triggered before the timeout actually updated the activedescendant, we need to fire\n // our own dispatchVirtualFocus so focusVisible gets reapplied on the input\n if (getVirtuallyFocusedElement(document) === inputRef.current) {\n dispatchVirtualFocus(inputRef.current!, null);\n }\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 (collectionRef.current !== null) {\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 if (item) {\n shouldPerformDefaultAction = item?.dispatchEvent(\n new KeyboardEvent(e.nativeEvent.type, e.nativeEvent)\n ) || false;\n }\n }\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 case 'Enter':\n // Trigger click action on item when Enter key was pressed.\n if (focusedNodeId != null) {\n let item = document.getElementById(focusedNodeId);\n item?.click();\n }\n break;\n }\n } else {\n // TODO: check if we can do this, want to stop textArea from using its default Enter behavior so items are properly triggered\n e.preventDefault();\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, node: Node<T>) => {\n if (filter) {\n return filter(nodeTextValue, state.inputValue, node);\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 // instead of focusing the last focused node, just focus the collection instead and have the collection handle what item to focus via useSelectableCollection/Item\n dispatchVirtualBlur(target, collectionRef.current);\n dispatchVirtualFocus(collectionRef.current!, target);\n });\n }\n };\n\n // Only apply the autocomplete specific behaviors if the collection component wrapped by it is actually\n // being filtered/allows filtering by the Autocomplete.\n let inputProps = {\n value: state.inputValue,\n onChange\n } as AriaTextFieldProps<FocusableElement>;\n\n let virtualFocusProps = {\n onKeyDown,\n 'aria-activedescendant': state.focusedNodeId ?? undefined,\n onBlur,\n onFocus\n };\n\n if (collectionId) {\n inputProps = {\n ...inputProps,\n ...(shouldUseVirtualFocus && virtualFocusProps),\n enterKeyHint: 'go',\n 'aria-controls': collectionId,\n // TODO: readd proper logic for completionMode = complete (aria-autocomplete: both)\n 'aria-autocomplete': 'list',\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 autoComplete: 'off'\n };\n }\n\n return {\n inputProps,\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"}
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, FocusableElement, FocusEvents, KeyboardEvents, Node, RefObject, ValueBase} 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, isAndroid, isCtrlKeyPressed, isIOS, mergeProps, mergeRefs, useEffectEvent, useEvent, useId, useLabels, useObjectRef} from '@react-aria/utils';\nimport {dispatchVirtualBlur, dispatchVirtualFocus, getVirtuallyFocusedElement, 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, useState} 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}\n\nexport interface InputProps<T = FocusableElement> extends DOMProps,\n FocusEvents<T>,\n KeyboardEvents,\n Pick<ValueBase<string>, 'onChange' | 'value'>,\n Pick<AriaTextFieldProps, 'enterKeyHint' | 'aria-controls' | 'aria-autocomplete' | 'aria-activedescendant' | 'spellCheck' | 'autoCorrect' | 'autoComplete'> {}\n\nexport interface AriaAutocompleteProps<T> 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, node: Node<T>) => boolean,\n\n /**\n * Whether or not to focus the first item in the collection after a filter is performed. Note this is only applicable\n * if virtual focus behavior is not turned off via `disableVirtualFocus`.\n * @default false\n */\n disableAutoFocusFirst?: boolean,\n\n /**\n * Whether the autocomplete should disable virtual focus, instead making the wrapped collection directly tabbable.\n * @default false\n */\n disableVirtualFocus?: boolean\n}\n\nexport interface AriaAutocompleteOptions<T> extends Omit<AriaAutocompleteProps<T>, '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<T> {\n /** Props for the autocomplete input element. These should be passed to the input's aria hooks (e.g. useTextField/useSearchField/etc) respectively. */\n inputProps: InputProps,\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, node: Node<T>) => 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<T>(props: AriaAutocompleteOptions<T>, state: AutocompleteState): AutocompleteAria<T> {\n let {\n inputRef,\n collectionRef,\n filter,\n disableAutoFocusFirst = false,\n disableVirtualFocus = 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 isMobileScreenReader = getInteractionModality() === 'virtual' && (isIOS() || isAndroid());\n let [shouldUseVirtualFocus, setShouldUseVirtualFocus] = useState(!isMobileScreenReader && !disableVirtualFocus);\n // Tracks if a collection has been connected to the autocomplete. If false, we don't want to add various attributes to the autocomplete input\n // since it isn't attached to a filterable collection (e.g. Tabs)\n let [hasCollection, setHasCollection] = useState(false);\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 if (queuedActiveDescendant.current && !document.getElementById(queuedActiveDescendant.current)) {\n // If we recieve a focus event refocusing the collection, either we have newly refocused the input and are waiting for the\n // wrapped collection to refocus the previously focused node if any OR\n // we are in a state where we've filtered to such a point that there aren't any matching items in the collection to focus.\n // In this case we want to clear tracked item if any and clear active descendant\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 // If useSelectableCollection isn't passed shouldUseVirtualFocus even when useAutocomplete provides it\n // that means the collection doesn't support it (e.g. Table). If that is the case, we need to disable it here regardless\n // of what the user's provided so that the input doesn't recieve the onKeyDown and autocomplete props.\n if (collectionNode.getAttribute('tabindex') != null) {\n setShouldUseVirtualFocus(false);\n }\n setHasCollection(true);\n } else {\n lastCollectionNode.current?.removeEventListener('focusin', updateActiveDescendant);\n setHasCollection(false);\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 let lastInputType = useRef('');\n useEvent(inputRef, 'input', e => {\n let {inputType} = e as InputEvent;\n lastInputType.current = inputType;\n });\n\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 modifying the text via\n // copy paste/backspacing/undo/redo for screen reader announcements\n if (lastInputType.current === 'insertText' && !disableAutoFocusFirst) {\n focusFirstItem();\n } else if (lastInputType.current && (lastInputType.current.includes('insert') || lastInputType.current.includes('delete') || lastInputType.current.includes('history'))) {\n clearVirtualFocus(true);\n\n // If onChange was triggered before the timeout actually updated the activedescendant, we need to fire\n // our own dispatchVirtualFocus so focusVisible gets reapplied on the input\n if (getVirtuallyFocusedElement(document) === inputRef.current) {\n dispatchVirtualFocus(inputRef.current!, null);\n }\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 (collectionRef.current !== null) {\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 if (item) {\n shouldPerformDefaultAction = item?.dispatchEvent(\n new KeyboardEvent(e.nativeEvent.type, e.nativeEvent)\n ) || false;\n }\n }\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 case 'Enter':\n // Trigger click action on item when Enter key was pressed.\n if (focusedNodeId != null) {\n let item = document.getElementById(focusedNodeId);\n item?.click();\n }\n break;\n }\n } else {\n // TODO: check if we can do this, want to stop textArea from using its default Enter behavior so items are properly triggered\n e.preventDefault();\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, node: Node<T>) => {\n if (filter) {\n return filter(nodeTextValue, state.inputValue, node);\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 // instead of focusing the last focused node, just focus the collection instead and have the collection handle what item to focus via useSelectableCollection/Item\n dispatchVirtualBlur(target, collectionRef.current);\n dispatchVirtualFocus(collectionRef.current!, target);\n });\n }\n };\n\n // Only apply the autocomplete specific behaviors if the collection component wrapped by it is actually\n // being filtered/allows filtering by the Autocomplete.\n let inputProps = {\n value: state.inputValue,\n onChange\n } as AriaTextFieldProps<FocusableElement>;\n\n let virtualFocusProps = {\n onKeyDown,\n 'aria-activedescendant': state.focusedNodeId ?? undefined,\n onBlur,\n onFocus\n };\n\n if (hasCollection) {\n inputProps = {\n ...inputProps,\n ...(shouldUseVirtualFocus && virtualFocusProps),\n enterKeyHint: 'go',\n 'aria-controls': collectionId,\n // TODO: readd proper logic for completionMode = complete (aria-autocomplete: both)\n 'aria-autocomplete': 'list',\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 autoComplete: 'off'\n };\n }\n\n return {\n inputProps,\n collectionProps: mergeProps(collectionProps, {\n shouldUseVirtualFocus,\n disallowTypeAhead: shouldUseVirtualFocus\n }),\n collectionRef: mergedCollectionRef,\n filter: filter != null ? filterFn : undefined\n };\n}\n"],"names":[],"version":3,"file":"useAutocomplete.main.js.map"}
@@ -1,8 +1,8 @@
1
1
  import $4ELxY$intlStringsmodulejs from "./intlStrings.mjs";
2
- import {useSlotId as $4ELxY$useSlotId, isIOS as $4ELxY$isIOS, isAndroid as $4ELxY$isAndroid, 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, useEvent as $4ELxY$useEvent, isCtrlKeyPressed as $4ELxY$isCtrlKeyPressed, useLabels as $4ELxY$useLabels, mergeProps as $4ELxY$mergeProps} from "@react-aria/utils";
2
+ import {useId as $4ELxY$useId, isIOS as $4ELxY$isIOS, isAndroid as $4ELxY$isAndroid, 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, useEvent as $4ELxY$useEvent, isCtrlKeyPressed as $4ELxY$isCtrlKeyPressed, useLabels as $4ELxY$useLabels, mergeProps as $4ELxY$mergeProps} from "@react-aria/utils";
3
3
  import {moveVirtualFocus as $4ELxY$moveVirtualFocus, getVirtuallyFocusedElement as $4ELxY$getVirtuallyFocusedElement, dispatchVirtualFocus as $4ELxY$dispatchVirtualFocus, dispatchVirtualBlur as $4ELxY$dispatchVirtualBlur} from "@react-aria/focus";
4
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";
5
+ import {useRef as $4ELxY$useRef, useState as $4ELxY$useState, useEffect as $4ELxY$useEffect, useCallback as $4ELxY$useCallback, useMemo as $4ELxY$useMemo} from "react";
6
6
  import {useLocalizedStringFormatter as $4ELxY$useLocalizedStringFormatter} from "@react-aria/i18n";
7
7
 
8
8
 
@@ -27,7 +27,7 @@ function $parcel$interopDefault(a) {
27
27
 
28
28
  function $48f6ba390f8c5b59$export$1e40b3ca02d92d21(props, state) {
29
29
  let { inputRef: inputRef, collectionRef: collectionRef, filter: filter, disableAutoFocusFirst: disableAutoFocusFirst = false, disableVirtualFocus: disableVirtualFocus = false } = props;
30
- let collectionId = (0, $4ELxY$useSlotId)();
30
+ let collectionId = (0, $4ELxY$useId)();
31
31
  let timeout = (0, $4ELxY$useRef)(undefined);
32
32
  let delayNextActiveDescendant = (0, $4ELxY$useRef)(false);
33
33
  let queuedActiveDescendant = (0, $4ELxY$useRef)(null);
@@ -35,7 +35,10 @@ function $48f6ba390f8c5b59$export$1e40b3ca02d92d21(props, state) {
35
35
  // For mobile screen readers, we don't want virtual focus, instead opting to disable FocusScope's restoreFocus and manually
36
36
  // moving focus back to the subtriggers
37
37
  let isMobileScreenReader = (0, $4ELxY$getInteractionModality)() === 'virtual' && ((0, $4ELxY$isIOS)() || (0, $4ELxY$isAndroid)());
38
- let shouldUseVirtualFocus = !isMobileScreenReader && !disableVirtualFocus;
38
+ let [shouldUseVirtualFocus, setShouldUseVirtualFocus] = (0, $4ELxY$useState)(!isMobileScreenReader && !disableVirtualFocus);
39
+ // Tracks if a collection has been connected to the autocomplete. If false, we don't want to add various attributes to the autocomplete input
40
+ // since it isn't attached to a filterable collection (e.g. Tabs)
41
+ let [hasCollection, setHasCollection] = (0, $4ELxY$useState)(false);
39
42
  (0, $4ELxY$useEffect)(()=>{
40
43
  return ()=>clearTimeout(timeout.current);
41
44
  }, []);
@@ -66,17 +69,25 @@ function $48f6ba390f8c5b59$export$1e40b3ca02d92d21(props, state) {
66
69
  delayNextActiveDescendant.current = false;
67
70
  });
68
71
  let callbackRef = (0, $4ELxY$useCallback)((collectionNode)=>{
69
- var _lastCollectionNode_current;
70
72
  if (collectionNode != null) {
71
73
  var // When typing forward, we want to delay the setting of active descendant to not interrupt the native screen reader announcement
72
74
  // of the letter you just typed. If we recieve another focus event then we clear the queued update
73
75
  // We track lastCollectionNode to do proper cleanup since callbackRefs just pass null when unmounting. This also handles
74
76
  // React 19's extra call of the callback ref in strict mode
75
- _lastCollectionNode_current1;
76
- (_lastCollectionNode_current1 = lastCollectionNode.current) === null || _lastCollectionNode_current1 === void 0 ? void 0 : _lastCollectionNode_current1.removeEventListener('focusin', updateActiveDescendant);
77
+ _lastCollectionNode_current;
78
+ (_lastCollectionNode_current = lastCollectionNode.current) === null || _lastCollectionNode_current === void 0 ? void 0 : _lastCollectionNode_current.removeEventListener('focusin', updateActiveDescendant);
77
79
  lastCollectionNode.current = collectionNode;
78
80
  collectionNode.addEventListener('focusin', updateActiveDescendant);
79
- } else (_lastCollectionNode_current = lastCollectionNode.current) === null || _lastCollectionNode_current === void 0 ? void 0 : _lastCollectionNode_current.removeEventListener('focusin', updateActiveDescendant);
81
+ // If useSelectableCollection isn't passed shouldUseVirtualFocus even when useAutocomplete provides it
82
+ // that means the collection doesn't support it (e.g. Table). If that is the case, we need to disable it here regardless
83
+ // of what the user's provided so that the input doesn't recieve the onKeyDown and autocomplete props.
84
+ if (collectionNode.getAttribute('tabindex') != null) setShouldUseVirtualFocus(false);
85
+ setHasCollection(true);
86
+ } else {
87
+ var _lastCollectionNode_current1;
88
+ (_lastCollectionNode_current1 = lastCollectionNode.current) === null || _lastCollectionNode_current1 === void 0 ? void 0 : _lastCollectionNode_current1.removeEventListener('focusin', updateActiveDescendant);
89
+ setHasCollection(false);
90
+ }
80
91
  }, [
81
92
  updateActiveDescendant
82
93
  ]);
@@ -272,7 +283,7 @@ function $48f6ba390f8c5b59$export$1e40b3ca02d92d21(props, state) {
272
283
  onBlur: onBlur,
273
284
  onFocus: onFocus
274
285
  };
275
- if (collectionId) inputProps = {
286
+ if (hasCollection) inputProps = {
276
287
  ...inputProps,
277
288
  ...shouldUseVirtualFocus && virtualFocusProps,
278
289
  enterKeyHint: 'go',
@@ -289,7 +300,7 @@ function $48f6ba390f8c5b59$export$1e40b3ca02d92d21(props, state) {
289
300
  inputProps: inputProps,
290
301
  collectionProps: (0, $4ELxY$mergeProps)(collectionProps, {
291
302
  shouldUseVirtualFocus: shouldUseVirtualFocus,
292
- disallowTypeAhead: true
303
+ disallowTypeAhead: shouldUseVirtualFocus
293
304
  }),
294
305
  collectionRef: mergedCollectionRef,
295
306
  filter: filter != null ? filterFn : undefined
@@ -1,8 +1,8 @@
1
1
  import $4ELxY$intlStringsmodulejs from "./intlStrings.module.js";
2
- import {useSlotId as $4ELxY$useSlotId, isIOS as $4ELxY$isIOS, isAndroid as $4ELxY$isAndroid, 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, useEvent as $4ELxY$useEvent, isCtrlKeyPressed as $4ELxY$isCtrlKeyPressed, useLabels as $4ELxY$useLabels, mergeProps as $4ELxY$mergeProps} from "@react-aria/utils";
2
+ import {useId as $4ELxY$useId, isIOS as $4ELxY$isIOS, isAndroid as $4ELxY$isAndroid, 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, useEvent as $4ELxY$useEvent, isCtrlKeyPressed as $4ELxY$isCtrlKeyPressed, useLabels as $4ELxY$useLabels, mergeProps as $4ELxY$mergeProps} from "@react-aria/utils";
3
3
  import {moveVirtualFocus as $4ELxY$moveVirtualFocus, getVirtuallyFocusedElement as $4ELxY$getVirtuallyFocusedElement, dispatchVirtualFocus as $4ELxY$dispatchVirtualFocus, dispatchVirtualBlur as $4ELxY$dispatchVirtualBlur} from "@react-aria/focus";
4
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";
5
+ import {useRef as $4ELxY$useRef, useState as $4ELxY$useState, useEffect as $4ELxY$useEffect, useCallback as $4ELxY$useCallback, useMemo as $4ELxY$useMemo} from "react";
6
6
  import {useLocalizedStringFormatter as $4ELxY$useLocalizedStringFormatter} from "@react-aria/i18n";
7
7
 
8
8
 
@@ -27,7 +27,7 @@ function $parcel$interopDefault(a) {
27
27
 
28
28
  function $48f6ba390f8c5b59$export$1e40b3ca02d92d21(props, state) {
29
29
  let { inputRef: inputRef, collectionRef: collectionRef, filter: filter, disableAutoFocusFirst: disableAutoFocusFirst = false, disableVirtualFocus: disableVirtualFocus = false } = props;
30
- let collectionId = (0, $4ELxY$useSlotId)();
30
+ let collectionId = (0, $4ELxY$useId)();
31
31
  let timeout = (0, $4ELxY$useRef)(undefined);
32
32
  let delayNextActiveDescendant = (0, $4ELxY$useRef)(false);
33
33
  let queuedActiveDescendant = (0, $4ELxY$useRef)(null);
@@ -35,7 +35,10 @@ function $48f6ba390f8c5b59$export$1e40b3ca02d92d21(props, state) {
35
35
  // For mobile screen readers, we don't want virtual focus, instead opting to disable FocusScope's restoreFocus and manually
36
36
  // moving focus back to the subtriggers
37
37
  let isMobileScreenReader = (0, $4ELxY$getInteractionModality)() === 'virtual' && ((0, $4ELxY$isIOS)() || (0, $4ELxY$isAndroid)());
38
- let shouldUseVirtualFocus = !isMobileScreenReader && !disableVirtualFocus;
38
+ let [shouldUseVirtualFocus, setShouldUseVirtualFocus] = (0, $4ELxY$useState)(!isMobileScreenReader && !disableVirtualFocus);
39
+ // Tracks if a collection has been connected to the autocomplete. If false, we don't want to add various attributes to the autocomplete input
40
+ // since it isn't attached to a filterable collection (e.g. Tabs)
41
+ let [hasCollection, setHasCollection] = (0, $4ELxY$useState)(false);
39
42
  (0, $4ELxY$useEffect)(()=>{
40
43
  return ()=>clearTimeout(timeout.current);
41
44
  }, []);
@@ -66,17 +69,25 @@ function $48f6ba390f8c5b59$export$1e40b3ca02d92d21(props, state) {
66
69
  delayNextActiveDescendant.current = false;
67
70
  });
68
71
  let callbackRef = (0, $4ELxY$useCallback)((collectionNode)=>{
69
- var _lastCollectionNode_current;
70
72
  if (collectionNode != null) {
71
73
  var // When typing forward, we want to delay the setting of active descendant to not interrupt the native screen reader announcement
72
74
  // of the letter you just typed. If we recieve another focus event then we clear the queued update
73
75
  // We track lastCollectionNode to do proper cleanup since callbackRefs just pass null when unmounting. This also handles
74
76
  // React 19's extra call of the callback ref in strict mode
75
- _lastCollectionNode_current1;
76
- (_lastCollectionNode_current1 = lastCollectionNode.current) === null || _lastCollectionNode_current1 === void 0 ? void 0 : _lastCollectionNode_current1.removeEventListener('focusin', updateActiveDescendant);
77
+ _lastCollectionNode_current;
78
+ (_lastCollectionNode_current = lastCollectionNode.current) === null || _lastCollectionNode_current === void 0 ? void 0 : _lastCollectionNode_current.removeEventListener('focusin', updateActiveDescendant);
77
79
  lastCollectionNode.current = collectionNode;
78
80
  collectionNode.addEventListener('focusin', updateActiveDescendant);
79
- } else (_lastCollectionNode_current = lastCollectionNode.current) === null || _lastCollectionNode_current === void 0 ? void 0 : _lastCollectionNode_current.removeEventListener('focusin', updateActiveDescendant);
81
+ // If useSelectableCollection isn't passed shouldUseVirtualFocus even when useAutocomplete provides it
82
+ // that means the collection doesn't support it (e.g. Table). If that is the case, we need to disable it here regardless
83
+ // of what the user's provided so that the input doesn't recieve the onKeyDown and autocomplete props.
84
+ if (collectionNode.getAttribute('tabindex') != null) setShouldUseVirtualFocus(false);
85
+ setHasCollection(true);
86
+ } else {
87
+ var _lastCollectionNode_current1;
88
+ (_lastCollectionNode_current1 = lastCollectionNode.current) === null || _lastCollectionNode_current1 === void 0 ? void 0 : _lastCollectionNode_current1.removeEventListener('focusin', updateActiveDescendant);
89
+ setHasCollection(false);
90
+ }
80
91
  }, [
81
92
  updateActiveDescendant
82
93
  ]);
@@ -272,7 +283,7 @@ function $48f6ba390f8c5b59$export$1e40b3ca02d92d21(props, state) {
272
283
  onBlur: onBlur,
273
284
  onFocus: onFocus
274
285
  };
275
- if (collectionId) inputProps = {
286
+ if (hasCollection) inputProps = {
276
287
  ...inputProps,
277
288
  ...shouldUseVirtualFocus && virtualFocusProps,
278
289
  enterKeyHint: 'go',
@@ -289,7 +300,7 @@ function $48f6ba390f8c5b59$export$1e40b3ca02d92d21(props, state) {
289
300
  inputProps: inputProps,
290
301
  collectionProps: (0, $4ELxY$mergeProps)(collectionProps, {
291
302
  shouldUseVirtualFocus: shouldUseVirtualFocus,
292
- disallowTypeAhead: true
303
+ disallowTypeAhead: shouldUseVirtualFocus
293
304
  }),
294
305
  collectionRef: mergedCollectionRef,
295
306
  filter: filter != null ? filterFn : undefined
@@ -1 +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, FocusableElement, FocusEvents, KeyboardEvents, Node, RefObject, ValueBase} 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, isAndroid, isCtrlKeyPressed, isIOS, mergeProps, mergeRefs, useEffectEvent, useEvent, useLabels, useObjectRef, useSlotId} from '@react-aria/utils';\nimport {dispatchVirtualBlur, dispatchVirtualFocus, getVirtuallyFocusedElement, 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}\n\nexport interface InputProps<T = FocusableElement> extends DOMProps,\n FocusEvents<T>,\n KeyboardEvents,\n Pick<ValueBase<string>, 'onChange' | 'value'>,\n Pick<AriaTextFieldProps, 'enterKeyHint' | 'aria-controls' | 'aria-autocomplete' | 'aria-activedescendant' | 'spellCheck' | 'autoCorrect' | 'autoComplete'> {}\n\nexport interface AriaAutocompleteProps<T> 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, node: Node<T>) => boolean,\n\n /**\n * Whether or not to focus the first item in the collection after a filter is performed. Note this is only applicable\n * if virtual focus behavior is not turned off via `disableVirtualFocus`.\n * @default false\n */\n disableAutoFocusFirst?: boolean,\n\n /**\n * Whether the autocomplete should disable virtual focus, instead making the wrapped collection directly tabbable.\n * @default false\n */\n disableVirtualFocus?: boolean\n}\n\nexport interface AriaAutocompleteOptions<T> extends Omit<AriaAutocompleteProps<T>, '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<T> {\n /** Props for the autocomplete input element. These should be passed to the input's aria hooks (e.g. useTextField/useSearchField/etc) respectively. */\n inputProps: InputProps,\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, node: Node<T>) => 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<T>(props: AriaAutocompleteOptions<T>, state: AutocompleteState): AutocompleteAria<T> {\n let {\n inputRef,\n collectionRef,\n filter,\n disableAutoFocusFirst = false,\n disableVirtualFocus = false\n } = props;\n\n let collectionId = useSlotId();\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 isMobileScreenReader = getInteractionModality() === 'virtual' && (isIOS() || isAndroid());\n let shouldUseVirtualFocus = !isMobileScreenReader && !disableVirtualFocus;\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 if (queuedActiveDescendant.current && !document.getElementById(queuedActiveDescendant.current)) {\n // If we recieve a focus event refocusing the collection, either we have newly refocused the input and are waiting for the\n // wrapped collection to refocus the previously focused node if any OR\n // we are in a state where we've filtered to such a point that there aren't any matching items in the collection to focus.\n // In this case we want to clear tracked item if any and clear active descendant\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 let lastInputType = useRef('');\n useEvent(inputRef, 'input', e => {\n let {inputType} = e as InputEvent;\n lastInputType.current = inputType;\n });\n\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 modifying the text via\n // copy paste/backspacing/undo/redo for screen reader announcements\n if (lastInputType.current === 'insertText' && !disableAutoFocusFirst) {\n focusFirstItem();\n } else if (lastInputType.current && (lastInputType.current.includes('insert') || lastInputType.current.includes('delete') || lastInputType.current.includes('history'))) {\n clearVirtualFocus(true);\n\n // If onChange was triggered before the timeout actually updated the activedescendant, we need to fire\n // our own dispatchVirtualFocus so focusVisible gets reapplied on the input\n if (getVirtuallyFocusedElement(document) === inputRef.current) {\n dispatchVirtualFocus(inputRef.current!, null);\n }\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 (collectionRef.current !== null) {\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 if (item) {\n shouldPerformDefaultAction = item?.dispatchEvent(\n new KeyboardEvent(e.nativeEvent.type, e.nativeEvent)\n ) || false;\n }\n }\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 case 'Enter':\n // Trigger click action on item when Enter key was pressed.\n if (focusedNodeId != null) {\n let item = document.getElementById(focusedNodeId);\n item?.click();\n }\n break;\n }\n } else {\n // TODO: check if we can do this, want to stop textArea from using its default Enter behavior so items are properly triggered\n e.preventDefault();\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, node: Node<T>) => {\n if (filter) {\n return filter(nodeTextValue, state.inputValue, node);\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 // instead of focusing the last focused node, just focus the collection instead and have the collection handle what item to focus via useSelectableCollection/Item\n dispatchVirtualBlur(target, collectionRef.current);\n dispatchVirtualFocus(collectionRef.current!, target);\n });\n }\n };\n\n // Only apply the autocomplete specific behaviors if the collection component wrapped by it is actually\n // being filtered/allows filtering by the Autocomplete.\n let inputProps = {\n value: state.inputValue,\n onChange\n } as AriaTextFieldProps<FocusableElement>;\n\n let virtualFocusProps = {\n onKeyDown,\n 'aria-activedescendant': state.focusedNodeId ?? undefined,\n onBlur,\n onFocus\n };\n\n if (collectionId) {\n inputProps = {\n ...inputProps,\n ...(shouldUseVirtualFocus && virtualFocusProps),\n enterKeyHint: 'go',\n 'aria-controls': collectionId,\n // TODO: readd proper logic for completionMode = complete (aria-autocomplete: both)\n 'aria-autocomplete': 'list',\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 autoComplete: 'off'\n };\n }\n\n return {\n inputProps,\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.module.js.map"}
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, FocusableElement, FocusEvents, KeyboardEvents, Node, RefObject, ValueBase} 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, isAndroid, isCtrlKeyPressed, isIOS, mergeProps, mergeRefs, useEffectEvent, useEvent, useId, useLabels, useObjectRef} from '@react-aria/utils';\nimport {dispatchVirtualBlur, dispatchVirtualFocus, getVirtuallyFocusedElement, 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, useState} 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}\n\nexport interface InputProps<T = FocusableElement> extends DOMProps,\n FocusEvents<T>,\n KeyboardEvents,\n Pick<ValueBase<string>, 'onChange' | 'value'>,\n Pick<AriaTextFieldProps, 'enterKeyHint' | 'aria-controls' | 'aria-autocomplete' | 'aria-activedescendant' | 'spellCheck' | 'autoCorrect' | 'autoComplete'> {}\n\nexport interface AriaAutocompleteProps<T> 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, node: Node<T>) => boolean,\n\n /**\n * Whether or not to focus the first item in the collection after a filter is performed. Note this is only applicable\n * if virtual focus behavior is not turned off via `disableVirtualFocus`.\n * @default false\n */\n disableAutoFocusFirst?: boolean,\n\n /**\n * Whether the autocomplete should disable virtual focus, instead making the wrapped collection directly tabbable.\n * @default false\n */\n disableVirtualFocus?: boolean\n}\n\nexport interface AriaAutocompleteOptions<T> extends Omit<AriaAutocompleteProps<T>, '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<T> {\n /** Props for the autocomplete input element. These should be passed to the input's aria hooks (e.g. useTextField/useSearchField/etc) respectively. */\n inputProps: InputProps,\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, node: Node<T>) => 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<T>(props: AriaAutocompleteOptions<T>, state: AutocompleteState): AutocompleteAria<T> {\n let {\n inputRef,\n collectionRef,\n filter,\n disableAutoFocusFirst = false,\n disableVirtualFocus = 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 isMobileScreenReader = getInteractionModality() === 'virtual' && (isIOS() || isAndroid());\n let [shouldUseVirtualFocus, setShouldUseVirtualFocus] = useState(!isMobileScreenReader && !disableVirtualFocus);\n // Tracks if a collection has been connected to the autocomplete. If false, we don't want to add various attributes to the autocomplete input\n // since it isn't attached to a filterable collection (e.g. Tabs)\n let [hasCollection, setHasCollection] = useState(false);\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 if (queuedActiveDescendant.current && !document.getElementById(queuedActiveDescendant.current)) {\n // If we recieve a focus event refocusing the collection, either we have newly refocused the input and are waiting for the\n // wrapped collection to refocus the previously focused node if any OR\n // we are in a state where we've filtered to such a point that there aren't any matching items in the collection to focus.\n // In this case we want to clear tracked item if any and clear active descendant\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 // If useSelectableCollection isn't passed shouldUseVirtualFocus even when useAutocomplete provides it\n // that means the collection doesn't support it (e.g. Table). If that is the case, we need to disable it here regardless\n // of what the user's provided so that the input doesn't recieve the onKeyDown and autocomplete props.\n if (collectionNode.getAttribute('tabindex') != null) {\n setShouldUseVirtualFocus(false);\n }\n setHasCollection(true);\n } else {\n lastCollectionNode.current?.removeEventListener('focusin', updateActiveDescendant);\n setHasCollection(false);\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 let lastInputType = useRef('');\n useEvent(inputRef, 'input', e => {\n let {inputType} = e as InputEvent;\n lastInputType.current = inputType;\n });\n\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 modifying the text via\n // copy paste/backspacing/undo/redo for screen reader announcements\n if (lastInputType.current === 'insertText' && !disableAutoFocusFirst) {\n focusFirstItem();\n } else if (lastInputType.current && (lastInputType.current.includes('insert') || lastInputType.current.includes('delete') || lastInputType.current.includes('history'))) {\n clearVirtualFocus(true);\n\n // If onChange was triggered before the timeout actually updated the activedescendant, we need to fire\n // our own dispatchVirtualFocus so focusVisible gets reapplied on the input\n if (getVirtuallyFocusedElement(document) === inputRef.current) {\n dispatchVirtualFocus(inputRef.current!, null);\n }\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 (collectionRef.current !== null) {\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 if (item) {\n shouldPerformDefaultAction = item?.dispatchEvent(\n new KeyboardEvent(e.nativeEvent.type, e.nativeEvent)\n ) || false;\n }\n }\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 case 'Enter':\n // Trigger click action on item when Enter key was pressed.\n if (focusedNodeId != null) {\n let item = document.getElementById(focusedNodeId);\n item?.click();\n }\n break;\n }\n } else {\n // TODO: check if we can do this, want to stop textArea from using its default Enter behavior so items are properly triggered\n e.preventDefault();\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, node: Node<T>) => {\n if (filter) {\n return filter(nodeTextValue, state.inputValue, node);\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 // instead of focusing the last focused node, just focus the collection instead and have the collection handle what item to focus via useSelectableCollection/Item\n dispatchVirtualBlur(target, collectionRef.current);\n dispatchVirtualFocus(collectionRef.current!, target);\n });\n }\n };\n\n // Only apply the autocomplete specific behaviors if the collection component wrapped by it is actually\n // being filtered/allows filtering by the Autocomplete.\n let inputProps = {\n value: state.inputValue,\n onChange\n } as AriaTextFieldProps<FocusableElement>;\n\n let virtualFocusProps = {\n onKeyDown,\n 'aria-activedescendant': state.focusedNodeId ?? undefined,\n onBlur,\n onFocus\n };\n\n if (hasCollection) {\n inputProps = {\n ...inputProps,\n ...(shouldUseVirtualFocus && virtualFocusProps),\n enterKeyHint: 'go',\n 'aria-controls': collectionId,\n // TODO: readd proper logic for completionMode = complete (aria-autocomplete: both)\n 'aria-autocomplete': 'list',\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 autoComplete: 'off'\n };\n }\n\n return {\n inputProps,\n collectionProps: mergeProps(collectionProps, {\n shouldUseVirtualFocus,\n disallowTypeAhead: shouldUseVirtualFocus\n }),\n collectionRef: mergedCollectionRef,\n filter: filter != null ? filterFn : undefined\n };\n}\n"],"names":[],"version":3,"file":"useAutocomplete.module.js.map"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-aria/autocomplete",
3
- "version": "3.0.0-rc.2",
3
+ "version": "3.0.0-rc.3",
4
4
  "description": "Spectrum UI components in React",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/main.js",
@@ -26,19 +26,19 @@
26
26
  "url": "https://github.com/adobe/react-spectrum"
27
27
  },
28
28
  "dependencies": {
29
- "@react-aria/combobox": "^3.13.2",
30
- "@react-aria/focus": "^3.21.1",
31
- "@react-aria/i18n": "^3.12.12",
32
- "@react-aria/interactions": "^3.25.5",
33
- "@react-aria/listbox": "^3.14.8",
34
- "@react-aria/searchfield": "^3.8.8",
35
- "@react-aria/textfield": "^3.18.1",
36
- "@react-aria/utils": "^3.30.1",
29
+ "@react-aria/combobox": "^3.14.0",
30
+ "@react-aria/focus": "^3.21.2",
31
+ "@react-aria/i18n": "^3.12.13",
32
+ "@react-aria/interactions": "^3.25.6",
33
+ "@react-aria/listbox": "^3.15.0",
34
+ "@react-aria/searchfield": "^3.8.9",
35
+ "@react-aria/textfield": "^3.18.2",
36
+ "@react-aria/utils": "^3.31.0",
37
37
  "@react-stately/autocomplete": "3.0.0-beta.3",
38
- "@react-stately/combobox": "^3.11.1",
39
- "@react-types/autocomplete": "3.0.0-alpha.34",
40
- "@react-types/button": "^3.14.0",
41
- "@react-types/shared": "^3.32.0",
38
+ "@react-stately/combobox": "^3.12.0",
39
+ "@react-types/autocomplete": "3.0.0-alpha.35",
40
+ "@react-types/button": "^3.14.1",
41
+ "@react-types/shared": "^3.32.1",
42
42
  "@swc/helpers": "^0.5.0"
43
43
  },
44
44
  "peerDependencies": {
@@ -48,5 +48,5 @@
48
48
  "publishConfig": {
49
49
  "access": "public"
50
50
  },
51
- "gitHead": "7bbe432a2f3ac09448b09769b34d36d777267f2f"
51
+ "gitHead": "0bda51183baa23306342af32a82012ea0fe0f2dc"
52
52
  }
@@ -13,12 +13,12 @@
13
13
  import {AriaLabelingProps, BaseEvent, DOMProps, FocusableElement, FocusEvents, KeyboardEvents, Node, RefObject, ValueBase} from '@react-types/shared';
14
14
  import {AriaTextFieldProps} from '@react-aria/textfield';
15
15
  import {AutocompleteProps, AutocompleteState} from '@react-stately/autocomplete';
16
- import {CLEAR_FOCUS_EVENT, FOCUS_EVENT, getActiveElement, getOwnerDocument, isAndroid, isCtrlKeyPressed, isIOS, mergeProps, mergeRefs, useEffectEvent, useEvent, useLabels, useObjectRef, useSlotId} from '@react-aria/utils';
16
+ import {CLEAR_FOCUS_EVENT, FOCUS_EVENT, getActiveElement, getOwnerDocument, isAndroid, isCtrlKeyPressed, isIOS, mergeProps, mergeRefs, useEffectEvent, useEvent, useId, useLabels, useObjectRef} from '@react-aria/utils';
17
17
  import {dispatchVirtualBlur, dispatchVirtualFocus, getVirtuallyFocusedElement, moveVirtualFocus} from '@react-aria/focus';
18
18
  import {getInteractionModality} from '@react-aria/interactions';
19
19
  // @ts-ignore
20
20
  import intlMessages from '../intl/*.json';
21
- import {FocusEvent as ReactFocusEvent, KeyboardEvent as ReactKeyboardEvent, useCallback, useEffect, useMemo, useRef} from 'react';
21
+ import {FocusEvent as ReactFocusEvent, KeyboardEvent as ReactKeyboardEvent, useCallback, useEffect, useMemo, useRef, useState} from 'react';
22
22
  import {useLocalizedStringFormatter} from '@react-aria/i18n';
23
23
 
24
24
  export interface CollectionOptions extends DOMProps, AriaLabelingProps {
@@ -88,7 +88,7 @@ export function useAutocomplete<T>(props: AriaAutocompleteOptions<T>, state: Aut
88
88
  disableVirtualFocus = false
89
89
  } = props;
90
90
 
91
- let collectionId = useSlotId();
91
+ let collectionId = useId();
92
92
  let timeout = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
93
93
  let delayNextActiveDescendant = useRef(false);
94
94
  let queuedActiveDescendant = useRef<string | null>(null);
@@ -97,7 +97,11 @@ export function useAutocomplete<T>(props: AriaAutocompleteOptions<T>, state: Aut
97
97
  // For mobile screen readers, we don't want virtual focus, instead opting to disable FocusScope's restoreFocus and manually
98
98
  // moving focus back to the subtriggers
99
99
  let isMobileScreenReader = getInteractionModality() === 'virtual' && (isIOS() || isAndroid());
100
- let shouldUseVirtualFocus = !isMobileScreenReader && !disableVirtualFocus;
100
+ let [shouldUseVirtualFocus, setShouldUseVirtualFocus] = useState(!isMobileScreenReader && !disableVirtualFocus);
101
+ // Tracks if a collection has been connected to the autocomplete. If false, we don't want to add various attributes to the autocomplete input
102
+ // since it isn't attached to a filterable collection (e.g. Tabs)
103
+ let [hasCollection, setHasCollection] = useState(false);
104
+
101
105
  useEffect(() => {
102
106
  return () => clearTimeout(timeout.current);
103
107
  }, []);
@@ -145,8 +149,16 @@ export function useAutocomplete<T>(props: AriaAutocompleteOptions<T>, state: Aut
145
149
  lastCollectionNode.current?.removeEventListener('focusin', updateActiveDescendant);
146
150
  lastCollectionNode.current = collectionNode;
147
151
  collectionNode.addEventListener('focusin', updateActiveDescendant);
152
+ // If useSelectableCollection isn't passed shouldUseVirtualFocus even when useAutocomplete provides it
153
+ // that means the collection doesn't support it (e.g. Table). If that is the case, we need to disable it here regardless
154
+ // of what the user's provided so that the input doesn't recieve the onKeyDown and autocomplete props.
155
+ if (collectionNode.getAttribute('tabindex') != null) {
156
+ setShouldUseVirtualFocus(false);
157
+ }
158
+ setHasCollection(true);
148
159
  } else {
149
160
  lastCollectionNode.current?.removeEventListener('focusin', updateActiveDescendant);
161
+ setHasCollection(false);
150
162
  }
151
163
  }, [updateActiveDescendant]);
152
164
 
@@ -393,7 +405,7 @@ export function useAutocomplete<T>(props: AriaAutocompleteOptions<T>, state: Aut
393
405
  onFocus
394
406
  };
395
407
 
396
- if (collectionId) {
408
+ if (hasCollection) {
397
409
  inputProps = {
398
410
  ...inputProps,
399
411
  ...(shouldUseVirtualFocus && virtualFocusProps),
@@ -413,7 +425,7 @@ export function useAutocomplete<T>(props: AriaAutocompleteOptions<T>, state: Aut
413
425
  inputProps,
414
426
  collectionProps: mergeProps(collectionProps, {
415
427
  shouldUseVirtualFocus,
416
- disallowTypeAhead: true
428
+ disallowTypeAhead: shouldUseVirtualFocus
417
429
  }),
418
430
  collectionRef: mergedCollectionRef,
419
431
  filter: filter != null ? filterFn : undefined