@react-aria/selection 3.26.0 → 3.27.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -81,6 +81,13 @@ function $880e95eb8b93ba9a$export$ecf600387e221c37(options) {
81
81
  // Prevent focus going to the body when clicking on a disabled item.
82
82
  e.preventDefault();
83
83
  };
84
+ (0, $581M0$useEffect)(()=>{
85
+ if (isDisabled && manager.focusedKey === key) manager.setFocusedKey(null);
86
+ }, [
87
+ manager,
88
+ isDisabled,
89
+ key
90
+ ]);
84
91
  // With checkbox selection, onAction (i.e. navigation) becomes primary, and occurs on a single click of the row.
85
92
  // Clicking the checkbox enters selection mode, after which clicking anywhere on any row toggles selection for that row.
86
93
  // With highlight selection, onAction is secondary, and occurs on double click. Single click selects the row.
@@ -122,13 +129,13 @@ function $880e95eb8b93ba9a$export$ecf600387e221c37(options) {
122
129
  itemPressProps.onPressStart = (e)=>{
123
130
  modality.current = e.pointerType;
124
131
  longPressEnabledOnPressStart.current = longPressEnabled;
125
- if (e.pointerType === 'keyboard' && (!hasAction || $880e95eb8b93ba9a$var$isSelectionKey())) onSelect(e);
132
+ if (e.pointerType === 'keyboard' && (!hasAction || $880e95eb8b93ba9a$var$isSelectionKey(e.key))) onSelect(e);
126
133
  };
127
134
  // If allowsDifferentPressOrigin and interacting with mouse, make selection happen on pressUp (e.g. open menu on press down, selection on menu item happens on press up.)
128
135
  // Otherwise, have selection happen onPress (prevents listview row selection when clicking on interactable elements in the row)
129
136
  if (!allowsDifferentPressOrigin) itemPressProps.onPress = (e)=>{
130
137
  if (hasPrimaryAction || hasSecondaryAction && e.pointerType !== 'mouse') {
131
- if (e.pointerType === 'keyboard' && !$880e95eb8b93ba9a$var$isActionKey()) return;
138
+ if (e.pointerType === 'keyboard' && !$880e95eb8b93ba9a$var$isActionKey(e.key)) return;
132
139
  performAction(e);
133
140
  } else if (e.pointerType !== 'keyboard' && allowsSelection) onSelect(e);
134
141
  };
@@ -148,13 +155,13 @@ function $880e95eb8b93ba9a$export$ecf600387e221c37(options) {
148
155
  // Select on mouse down unless there is a primary action which will occur on mouse up.
149
156
  // For keyboard, select on key down. If there is an action, the Space key selects on key down,
150
157
  // and the Enter key performs onAction on key up.
151
- if (allowsSelection && (e.pointerType === 'mouse' && !hasPrimaryAction || e.pointerType === 'keyboard' && (!allowsActions || $880e95eb8b93ba9a$var$isSelectionKey()))) onSelect(e);
158
+ if (allowsSelection && (e.pointerType === 'mouse' && !hasPrimaryAction || e.pointerType === 'keyboard' && (!allowsActions || $880e95eb8b93ba9a$var$isSelectionKey(e.key)))) onSelect(e);
152
159
  };
153
160
  itemPressProps.onPress = (e)=>{
154
161
  // Selection occurs on touch up. Primary actions always occur on pointer up.
155
162
  // Both primary and secondary actions occur on Enter key up. The only exception
156
163
  // is secondary actions, which occur on double click with a mouse.
157
- if (e.pointerType === 'touch' || e.pointerType === 'pen' || e.pointerType === 'virtual' || e.pointerType === 'keyboard' && hasAction && $880e95eb8b93ba9a$var$isActionKey() || e.pointerType === 'mouse' && hadPrimaryActionOnPressStart.current) {
164
+ if (e.pointerType === 'touch' || e.pointerType === 'pen' || e.pointerType === 'virtual' || e.pointerType === 'keyboard' && hasAction && $880e95eb8b93ba9a$var$isActionKey(e.key) || e.pointerType === 'mouse' && hadPrimaryActionOnPressStart.current) {
158
165
  if (hasAction) performAction(e);
159
166
  else if (allowsSelection) onSelect(e);
160
167
  }
@@ -239,13 +246,11 @@ function $880e95eb8b93ba9a$export$ecf600387e221c37(options) {
239
246
  hasAction: hasAction
240
247
  };
241
248
  }
242
- function $880e95eb8b93ba9a$var$isActionKey() {
243
- let event = window.event;
244
- return (event === null || event === void 0 ? void 0 : event.key) === 'Enter';
249
+ function $880e95eb8b93ba9a$var$isActionKey(key) {
250
+ return key === 'Enter';
245
251
  }
246
- function $880e95eb8b93ba9a$var$isSelectionKey() {
247
- let event = window.event;
248
- return (event === null || event === void 0 ? void 0 : event.key) === ' ' || (event === null || event === void 0 ? void 0 : event.code) === 'Space';
252
+ function $880e95eb8b93ba9a$var$isSelectionKey(key) {
253
+ return key === ' ';
249
254
  }
250
255
 
251
256
 
@@ -1 +1 @@
1
- {"mappings":"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","sources":["packages/@react-aria/selection/src/useSelectableItem.ts"],"sourcesContent":["/*\n * Copyright 2020 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 {chain, isCtrlKeyPressed, mergeProps, openLink, useId, useRouter} from '@react-aria/utils';\nimport {DOMAttributes, DOMProps, FocusableElement, Key, LongPressEvent, PointerType, PressEvent, RefObject} from '@react-types/shared';\nimport {focusSafely, PressHookProps, useLongPress, usePress} from '@react-aria/interactions';\nimport {getCollectionId, isNonContiguousSelectionModifier} from './utils';\nimport {moveVirtualFocus} from '@react-aria/focus';\nimport {MultipleSelectionManager} from '@react-stately/selection';\nimport {useEffect, useRef} from 'react';\n\nexport interface SelectableItemOptions extends DOMProps {\n /**\n * An interface for reading and updating multiple selection state.\n */\n selectionManager: MultipleSelectionManager,\n /**\n * A unique key for the item.\n */\n key: Key,\n /**\n * Ref to the item.\n */\n ref: RefObject<FocusableElement | null>,\n /**\n * By default, selection occurs on pointer down. This can be strange if selecting an\n * item causes the UI to disappear immediately (e.g. menus).\n */\n shouldSelectOnPressUp?: boolean,\n /**\n * Whether selection requires the pointer/mouse down and up events to occur on the same target or triggers selection on\n * the target of the pointer/mouse up event.\n */\n allowsDifferentPressOrigin?: boolean,\n /**\n * Whether the option is contained in a virtual scroller.\n */\n isVirtualized?: boolean,\n /**\n * Function to focus the item.\n */\n focus?: () => void,\n /**\n * Whether the option should use virtual focus instead of being focused directly.\n */\n shouldUseVirtualFocus?: boolean,\n /** Whether the item is disabled. */\n isDisabled?: boolean,\n /**\n * Handler that is called when a user performs an action on the item. The exact user event depends on\n * the collection's `selectionBehavior` prop and the interaction modality.\n */\n onAction?: () => void,\n /**\n * The behavior of links in the collection.\n * - 'action': link behaves like onAction.\n * - 'selection': link follows selection interactions (e.g. if URL drives selection).\n * - 'override': links override all other interactions (link items are not selectable).\n * - 'none': links are disabled for both selection and actions (e.g. handled elsewhere).\n * @default 'action'\n */\n linkBehavior?: 'action' | 'selection' | 'override' | 'none'\n}\n\nexport interface SelectableItemStates {\n /** Whether the item is currently in a pressed state. */\n isPressed: boolean,\n /** Whether the item is currently selected. */\n isSelected: boolean,\n /** Whether the item is currently focused. */\n isFocused: boolean,\n /**\n * Whether the item is non-interactive, i.e. both selection and actions are disabled and the item may\n * not be focused. Dependent on `disabledKeys` and `disabledBehavior`.\n */\n isDisabled: boolean,\n /**\n * Whether the item may be selected, dependent on `selectionMode`, `disabledKeys`, and `disabledBehavior`.\n */\n allowsSelection: boolean,\n /**\n * Whether the item has an action, dependent on `onAction`, `disabledKeys`,\n * and `disabledBehavior`. It may also change depending on the current selection state\n * of the list (e.g. when selection is primary). This can be used to enable or disable hover\n * styles or other visual indications of interactivity.\n */\n hasAction: boolean\n}\n\nexport interface SelectableItemAria extends SelectableItemStates {\n /**\n * Props to be spread on the item root node.\n */\n itemProps: DOMAttributes\n}\n\n/**\n * Handles interactions with an item in a selectable collection.\n */\nexport function useSelectableItem(options: SelectableItemOptions): SelectableItemAria {\n let {\n id,\n selectionManager: manager,\n key,\n ref,\n shouldSelectOnPressUp,\n shouldUseVirtualFocus,\n focus,\n isDisabled,\n onAction,\n allowsDifferentPressOrigin,\n linkBehavior = 'action'\n } = options;\n let router = useRouter();\n id = useId(id);\n let onSelect = (e: PressEvent | LongPressEvent | PointerEvent) => {\n if (e.pointerType === 'keyboard' && isNonContiguousSelectionModifier(e)) {\n manager.toggleSelection(key);\n } else {\n if (manager.selectionMode === 'none') {\n return;\n }\n\n if (manager.isLink(key)) {\n if (linkBehavior === 'selection' && ref.current) {\n let itemProps = manager.getItemProps(key);\n router.open(ref.current, e, itemProps.href, itemProps.routerOptions);\n // Always set selected keys back to what they were so that select and combobox close.\n manager.setSelectedKeys(manager.selectedKeys);\n return;\n } else if (linkBehavior === 'override' || linkBehavior === 'none') {\n return;\n }\n }\n\n if (manager.selectionMode === 'single') {\n if (manager.isSelected(key) && !manager.disallowEmptySelection) {\n manager.toggleSelection(key);\n } else {\n manager.replaceSelection(key);\n }\n } else if (e && e.shiftKey) {\n manager.extendSelection(key);\n } else if (manager.selectionBehavior === 'toggle' || (e && (isCtrlKeyPressed(e) || e.pointerType === 'touch' || e.pointerType === 'virtual'))) {\n // if touch or virtual (VO) then we just want to toggle, otherwise it's impossible to multi select because they don't have modifier keys\n manager.toggleSelection(key);\n } else {\n manager.replaceSelection(key);\n }\n }\n };\n\n // Focus the associated DOM node when this item becomes the focusedKey\n // TODO: can't make this useLayoutEffect bacause it breaks menus inside dialogs\n // However, if this is a useEffect, it runs twice and dispatches two blur events and immediately sets\n // aria-activeDescendant in useAutocomplete... I've worked around this for now\n useEffect(() => {\n let isFocused = key === manager.focusedKey;\n if (isFocused && manager.isFocused) {\n if (!shouldUseVirtualFocus) {\n if (focus) {\n focus();\n } else if (document.activeElement !== ref.current && ref.current) {\n focusSafely(ref.current);\n }\n } else {\n moveVirtualFocus(ref.current);\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [ref, key, manager.focusedKey, manager.childFocusStrategy, manager.isFocused, shouldUseVirtualFocus]);\n\n isDisabled = isDisabled || manager.isDisabled(key);\n // Set tabIndex to 0 if the element is focused, or -1 otherwise so that only the last focused\n // item is tabbable. If using virtual focus, don't set a tabIndex at all so that VoiceOver\n // on iOS 14 doesn't try to move real DOM focus to the item anyway.\n let itemProps: SelectableItemAria['itemProps'] = {};\n if (!shouldUseVirtualFocus && !isDisabled) {\n itemProps = {\n tabIndex: key === manager.focusedKey ? 0 : -1,\n onFocus(e) {\n if (e.target === ref.current) {\n manager.setFocusedKey(key);\n }\n }\n };\n } else if (isDisabled) {\n itemProps.onMouseDown = (e) => {\n // Prevent focus going to the body when clicking on a disabled item.\n e.preventDefault();\n };\n }\n\n // With checkbox selection, onAction (i.e. navigation) becomes primary, and occurs on a single click of the row.\n // Clicking the checkbox enters selection mode, after which clicking anywhere on any row toggles selection for that row.\n // With highlight selection, onAction is secondary, and occurs on double click. Single click selects the row.\n // With touch, onAction occurs on single tap, and long press enters selection mode.\n let isLinkOverride = manager.isLink(key) && linkBehavior === 'override';\n let isActionOverride = onAction && options['UNSTABLE_itemBehavior'] === 'action';\n let hasLinkAction = manager.isLink(key) && linkBehavior !== 'selection' && linkBehavior !== 'none';\n let allowsSelection = !isDisabled && manager.canSelectItem(key) && !isLinkOverride && !isActionOverride;\n let allowsActions = (onAction || hasLinkAction) && !isDisabled;\n let hasPrimaryAction = allowsActions && (\n manager.selectionBehavior === 'replace'\n ? !allowsSelection\n : !allowsSelection || manager.isEmpty\n );\n let hasSecondaryAction = allowsActions && allowsSelection && manager.selectionBehavior === 'replace';\n let hasAction = hasPrimaryAction || hasSecondaryAction;\n let modality = useRef<PointerType | null>(null);\n\n let longPressEnabled = hasAction && allowsSelection;\n let longPressEnabledOnPressStart = useRef(false);\n let hadPrimaryActionOnPressStart = useRef(false);\n let collectionItemProps = manager.getItemProps(key);\n\n let performAction = (e) => {\n if (onAction) {\n onAction();\n ref.current?.dispatchEvent(new CustomEvent('react-aria-item-action', {bubbles: true}));\n }\n\n if (hasLinkAction && ref.current) {\n router.open(ref.current, e, collectionItemProps.href, collectionItemProps.routerOptions);\n }\n };\n\n // By default, selection occurs on pointer down. This can be strange if selecting an\n // item causes the UI to disappear immediately (e.g. menus).\n // If shouldSelectOnPressUp is true, we use onPressUp instead of onPressStart.\n // onPress requires a pointer down event on the same element as pointer up. For menus,\n // we want to be able to have the pointer down on the trigger that opens the menu and\n // the pointer up on the menu item rather than requiring a separate press.\n // For keyboard events, selection still occurs on key down.\n let itemPressProps: PressHookProps = {ref};\n if (shouldSelectOnPressUp) {\n itemPressProps.onPressStart = (e) => {\n modality.current = e.pointerType;\n longPressEnabledOnPressStart.current = longPressEnabled;\n if (e.pointerType === 'keyboard' && (!hasAction || isSelectionKey())) {\n onSelect(e);\n }\n };\n\n // If allowsDifferentPressOrigin and interacting with mouse, make selection happen on pressUp (e.g. open menu on press down, selection on menu item happens on press up.)\n // Otherwise, have selection happen onPress (prevents listview row selection when clicking on interactable elements in the row)\n if (!allowsDifferentPressOrigin) {\n itemPressProps.onPress = (e) => {\n if (hasPrimaryAction || (hasSecondaryAction && e.pointerType !== 'mouse')) {\n if (e.pointerType === 'keyboard' && !isActionKey()) {\n return;\n }\n\n performAction(e);\n } else if (e.pointerType !== 'keyboard' && allowsSelection) {\n onSelect(e);\n }\n };\n } else {\n itemPressProps.onPressUp = hasPrimaryAction ? undefined : (e) => {\n if (e.pointerType === 'mouse' && allowsSelection) {\n onSelect(e);\n }\n };\n\n itemPressProps.onPress = hasPrimaryAction ? performAction : (e) => {\n if (e.pointerType !== 'keyboard' && e.pointerType !== 'mouse' && allowsSelection) {\n onSelect(e);\n }\n };\n }\n } else {\n itemPressProps.onPressStart = (e) => {\n modality.current = e.pointerType;\n longPressEnabledOnPressStart.current = longPressEnabled;\n hadPrimaryActionOnPressStart.current = hasPrimaryAction;\n\n // Select on mouse down unless there is a primary action which will occur on mouse up.\n // For keyboard, select on key down. If there is an action, the Space key selects on key down,\n // and the Enter key performs onAction on key up.\n if (\n allowsSelection && (\n (e.pointerType === 'mouse' && !hasPrimaryAction) ||\n (e.pointerType === 'keyboard' && (!allowsActions || isSelectionKey()))\n )\n ) {\n onSelect(e);\n }\n };\n\n itemPressProps.onPress = (e) => {\n // Selection occurs on touch up. Primary actions always occur on pointer up.\n // Both primary and secondary actions occur on Enter key up. The only exception\n // is secondary actions, which occur on double click with a mouse.\n if (\n e.pointerType === 'touch' ||\n e.pointerType === 'pen' ||\n e.pointerType === 'virtual' ||\n (e.pointerType === 'keyboard' && hasAction && isActionKey()) ||\n (e.pointerType === 'mouse' && hadPrimaryActionOnPressStart.current)\n ) {\n if (hasAction) {\n performAction(e);\n } else if (allowsSelection) {\n onSelect(e);\n }\n }\n };\n }\n\n itemProps['data-collection'] = getCollectionId(manager.collection);\n itemProps['data-key'] = key;\n itemPressProps.preventFocusOnPress = shouldUseVirtualFocus;\n\n // When using virtual focus, make sure the focused key gets updated on press.\n if (shouldUseVirtualFocus) {\n itemPressProps = mergeProps(itemPressProps, {\n onPressStart(e) {\n if (e.pointerType !== 'touch') {\n manager.setFocused(true);\n manager.setFocusedKey(key);\n }\n },\n onPress(e) {\n if (e.pointerType === 'touch') {\n manager.setFocused(true);\n manager.setFocusedKey(key);\n }\n }\n });\n }\n\n if (collectionItemProps) {\n for (let key of ['onPressStart', 'onPressEnd', 'onPressChange', 'onPress', 'onPressUp', 'onClick']) {\n if (collectionItemProps[key]) {\n itemPressProps[key] = chain(itemPressProps[key], collectionItemProps[key]);\n }\n }\n }\n\n let {pressProps, isPressed} = usePress(itemPressProps);\n\n // Double clicking with a mouse with selectionBehavior = 'replace' performs an action.\n let onDoubleClick = hasSecondaryAction ? (e) => {\n if (modality.current === 'mouse') {\n e.stopPropagation();\n e.preventDefault();\n performAction(e);\n }\n } : undefined;\n\n // Long pressing an item with touch when selectionBehavior = 'replace' switches the selection behavior\n // to 'toggle'. This changes the single tap behavior from performing an action (i.e. navigating) to\n // selecting, and may toggle the appearance of a UI affordance like checkboxes on each item.\n let {longPressProps} = useLongPress({\n isDisabled: !longPressEnabled,\n onLongPress(e) {\n if (e.pointerType === 'touch') {\n onSelect(e);\n manager.setSelectionBehavior('toggle');\n }\n }\n });\n\n // Prevent native drag and drop on long press if we also select on long press.\n // Once the user is in selection mode, they can long press again to drag.\n // Use a capturing listener to ensure this runs before useDrag, regardless of\n // the order the props get merged.\n let onDragStartCapture = e => {\n if (modality.current === 'touch' && longPressEnabledOnPressStart.current) {\n e.preventDefault();\n }\n };\n\n // Prevent default on link clicks so that we control exactly\n // when they open (to match selection behavior).\n let onClick = linkBehavior !== 'none' && manager.isLink(key) ? e => {\n if (!(openLink as any).isOpening) {\n e.preventDefault();\n }\n } : undefined;\n\n return {\n itemProps: mergeProps(\n itemProps,\n allowsSelection || hasPrimaryAction || (shouldUseVirtualFocus && !isDisabled) ? pressProps : {},\n longPressEnabled ? longPressProps : {},\n {onDoubleClick, onDragStartCapture, onClick, id},\n // Prevent DOM focus from moving on mouse down when using virtual focus\n shouldUseVirtualFocus ? {onMouseDown: e => e.preventDefault()} : undefined\n ),\n isPressed,\n isSelected: manager.isSelected(key),\n isFocused: manager.isFocused && manager.focusedKey === key,\n isDisabled,\n allowsSelection,\n hasAction\n };\n}\n\nfunction isActionKey() {\n let event = window.event as KeyboardEvent;\n return event?.key === 'Enter';\n}\n\nfunction isSelectionKey() {\n let event = window.event as KeyboardEvent;\n return event?.key === ' ' || event?.code === 'Space';\n}\n"],"names":[],"version":3,"file":"useSelectableItem.module.js.map"}
1
+ {"mappings":"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","sources":["packages/@react-aria/selection/src/useSelectableItem.ts"],"sourcesContent":["/*\n * Copyright 2020 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 {chain, isCtrlKeyPressed, mergeProps, openLink, useId, useRouter} from '@react-aria/utils';\nimport {DOMAttributes, DOMProps, FocusableElement, Key, LongPressEvent, PointerType, PressEvent, RefObject} from '@react-types/shared';\nimport {focusSafely, PressHookProps, useLongPress, usePress} from '@react-aria/interactions';\nimport {getCollectionId, isNonContiguousSelectionModifier} from './utils';\nimport {moveVirtualFocus} from '@react-aria/focus';\nimport {MultipleSelectionManager} from '@react-stately/selection';\nimport {useEffect, useRef} from 'react';\n\nexport interface SelectableItemOptions extends DOMProps {\n /**\n * An interface for reading and updating multiple selection state.\n */\n selectionManager: MultipleSelectionManager,\n /**\n * A unique key for the item.\n */\n key: Key,\n /**\n * Ref to the item.\n */\n ref: RefObject<FocusableElement | null>,\n /**\n * By default, selection occurs on pointer down. This can be strange if selecting an\n * item causes the UI to disappear immediately (e.g. menus).\n */\n shouldSelectOnPressUp?: boolean,\n /**\n * Whether selection requires the pointer/mouse down and up events to occur on the same target or triggers selection on\n * the target of the pointer/mouse up event.\n */\n allowsDifferentPressOrigin?: boolean,\n /**\n * Whether the option is contained in a virtual scroller.\n */\n isVirtualized?: boolean,\n /**\n * Function to focus the item.\n */\n focus?: () => void,\n /**\n * Whether the option should use virtual focus instead of being focused directly.\n */\n shouldUseVirtualFocus?: boolean,\n /** Whether the item is disabled. */\n isDisabled?: boolean,\n /**\n * Handler that is called when a user performs an action on the item. The exact user event depends on\n * the collection's `selectionBehavior` prop and the interaction modality.\n */\n onAction?: () => void,\n /**\n * The behavior of links in the collection.\n * - 'action': link behaves like onAction.\n * - 'selection': link follows selection interactions (e.g. if URL drives selection).\n * - 'override': links override all other interactions (link items are not selectable).\n * - 'none': links are disabled for both selection and actions (e.g. handled elsewhere).\n * @default 'action'\n */\n linkBehavior?: 'action' | 'selection' | 'override' | 'none'\n}\n\nexport interface SelectableItemStates {\n /** Whether the item is currently in a pressed state. */\n isPressed: boolean,\n /** Whether the item is currently selected. */\n isSelected: boolean,\n /** Whether the item is currently focused. */\n isFocused: boolean,\n /**\n * Whether the item is non-interactive, i.e. both selection and actions are disabled and the item may\n * not be focused. Dependent on `disabledKeys` and `disabledBehavior`.\n */\n isDisabled: boolean,\n /**\n * Whether the item may be selected, dependent on `selectionMode`, `disabledKeys`, and `disabledBehavior`.\n */\n allowsSelection: boolean,\n /**\n * Whether the item has an action, dependent on `onAction`, `disabledKeys`,\n * and `disabledBehavior`. It may also change depending on the current selection state\n * of the list (e.g. when selection is primary). This can be used to enable or disable hover\n * styles or other visual indications of interactivity.\n */\n hasAction: boolean\n}\n\nexport interface SelectableItemAria extends SelectableItemStates {\n /**\n * Props to be spread on the item root node.\n */\n itemProps: DOMAttributes\n}\n\n/**\n * Handles interactions with an item in a selectable collection.\n */\nexport function useSelectableItem(options: SelectableItemOptions): SelectableItemAria {\n let {\n id,\n selectionManager: manager,\n key,\n ref,\n shouldSelectOnPressUp,\n shouldUseVirtualFocus,\n focus,\n isDisabled,\n onAction,\n allowsDifferentPressOrigin,\n linkBehavior = 'action'\n } = options;\n let router = useRouter();\n id = useId(id);\n let onSelect = (e: PressEvent | LongPressEvent | PointerEvent) => {\n if (e.pointerType === 'keyboard' && isNonContiguousSelectionModifier(e)) {\n manager.toggleSelection(key);\n } else {\n if (manager.selectionMode === 'none') {\n return;\n }\n\n if (manager.isLink(key)) {\n if (linkBehavior === 'selection' && ref.current) {\n let itemProps = manager.getItemProps(key);\n router.open(ref.current, e, itemProps.href, itemProps.routerOptions);\n // Always set selected keys back to what they were so that select and combobox close.\n manager.setSelectedKeys(manager.selectedKeys);\n return;\n } else if (linkBehavior === 'override' || linkBehavior === 'none') {\n return;\n }\n }\n\n if (manager.selectionMode === 'single') {\n if (manager.isSelected(key) && !manager.disallowEmptySelection) {\n manager.toggleSelection(key);\n } else {\n manager.replaceSelection(key);\n }\n } else if (e && e.shiftKey) {\n manager.extendSelection(key);\n } else if (manager.selectionBehavior === 'toggle' || (e && (isCtrlKeyPressed(e) || e.pointerType === 'touch' || e.pointerType === 'virtual'))) {\n // if touch or virtual (VO) then we just want to toggle, otherwise it's impossible to multi select because they don't have modifier keys\n manager.toggleSelection(key);\n } else {\n manager.replaceSelection(key);\n }\n }\n };\n\n // Focus the associated DOM node when this item becomes the focusedKey\n // TODO: can't make this useLayoutEffect bacause it breaks menus inside dialogs\n // However, if this is a useEffect, it runs twice and dispatches two blur events and immediately sets\n // aria-activeDescendant in useAutocomplete... I've worked around this for now\n useEffect(() => {\n let isFocused = key === manager.focusedKey;\n if (isFocused && manager.isFocused) {\n if (!shouldUseVirtualFocus) {\n if (focus) {\n focus();\n } else if (document.activeElement !== ref.current && ref.current) {\n focusSafely(ref.current);\n }\n } else {\n moveVirtualFocus(ref.current);\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [ref, key, manager.focusedKey, manager.childFocusStrategy, manager.isFocused, shouldUseVirtualFocus]);\n\n isDisabled = isDisabled || manager.isDisabled(key);\n // Set tabIndex to 0 if the element is focused, or -1 otherwise so that only the last focused\n // item is tabbable. If using virtual focus, don't set a tabIndex at all so that VoiceOver\n // on iOS 14 doesn't try to move real DOM focus to the item anyway.\n let itemProps: SelectableItemAria['itemProps'] = {};\n if (!shouldUseVirtualFocus && !isDisabled) {\n itemProps = {\n tabIndex: key === manager.focusedKey ? 0 : -1,\n onFocus(e) {\n if (e.target === ref.current) {\n manager.setFocusedKey(key);\n }\n }\n };\n } else if (isDisabled) {\n itemProps.onMouseDown = (e) => {\n // Prevent focus going to the body when clicking on a disabled item.\n e.preventDefault();\n };\n }\n\n useEffect(() => {\n if (isDisabled && manager.focusedKey === key) {\n manager.setFocusedKey(null);\n }\n }, [manager, isDisabled, key]);\n\n // With checkbox selection, onAction (i.e. navigation) becomes primary, and occurs on a single click of the row.\n // Clicking the checkbox enters selection mode, after which clicking anywhere on any row toggles selection for that row.\n // With highlight selection, onAction is secondary, and occurs on double click. Single click selects the row.\n // With touch, onAction occurs on single tap, and long press enters selection mode.\n let isLinkOverride = manager.isLink(key) && linkBehavior === 'override';\n let isActionOverride = onAction && options['UNSTABLE_itemBehavior'] === 'action';\n let hasLinkAction = manager.isLink(key) && linkBehavior !== 'selection' && linkBehavior !== 'none';\n let allowsSelection = !isDisabled && manager.canSelectItem(key) && !isLinkOverride && !isActionOverride;\n let allowsActions = (onAction || hasLinkAction) && !isDisabled;\n let hasPrimaryAction = allowsActions && (\n manager.selectionBehavior === 'replace'\n ? !allowsSelection\n : !allowsSelection || manager.isEmpty\n );\n let hasSecondaryAction = allowsActions && allowsSelection && manager.selectionBehavior === 'replace';\n let hasAction = hasPrimaryAction || hasSecondaryAction;\n let modality = useRef<PointerType | null>(null);\n\n let longPressEnabled = hasAction && allowsSelection;\n let longPressEnabledOnPressStart = useRef(false);\n let hadPrimaryActionOnPressStart = useRef(false);\n let collectionItemProps = manager.getItemProps(key);\n\n let performAction = (e) => {\n if (onAction) {\n onAction();\n ref.current?.dispatchEvent(new CustomEvent('react-aria-item-action', {bubbles: true}));\n }\n\n if (hasLinkAction && ref.current) {\n router.open(ref.current, e, collectionItemProps.href, collectionItemProps.routerOptions);\n }\n };\n\n // By default, selection occurs on pointer down. This can be strange if selecting an\n // item causes the UI to disappear immediately (e.g. menus).\n // If shouldSelectOnPressUp is true, we use onPressUp instead of onPressStart.\n // onPress requires a pointer down event on the same element as pointer up. For menus,\n // we want to be able to have the pointer down on the trigger that opens the menu and\n // the pointer up on the menu item rather than requiring a separate press.\n // For keyboard events, selection still occurs on key down.\n let itemPressProps: PressHookProps = {ref};\n if (shouldSelectOnPressUp) {\n itemPressProps.onPressStart = (e) => {\n modality.current = e.pointerType;\n longPressEnabledOnPressStart.current = longPressEnabled;\n if (e.pointerType === 'keyboard' && (!hasAction || isSelectionKey(e.key))) {\n onSelect(e);\n }\n };\n\n // If allowsDifferentPressOrigin and interacting with mouse, make selection happen on pressUp (e.g. open menu on press down, selection on menu item happens on press up.)\n // Otherwise, have selection happen onPress (prevents listview row selection when clicking on interactable elements in the row)\n if (!allowsDifferentPressOrigin) {\n itemPressProps.onPress = (e) => {\n if (hasPrimaryAction || (hasSecondaryAction && e.pointerType !== 'mouse')) {\n if (e.pointerType === 'keyboard' && !isActionKey(e.key)) {\n return;\n }\n\n performAction(e);\n } else if (e.pointerType !== 'keyboard' && allowsSelection) {\n onSelect(e);\n }\n };\n } else {\n itemPressProps.onPressUp = hasPrimaryAction ? undefined : (e) => {\n if (e.pointerType === 'mouse' && allowsSelection) {\n onSelect(e);\n }\n };\n\n itemPressProps.onPress = hasPrimaryAction ? performAction : (e) => {\n if (e.pointerType !== 'keyboard' && e.pointerType !== 'mouse' && allowsSelection) {\n onSelect(e);\n }\n };\n }\n } else {\n itemPressProps.onPressStart = (e) => {\n modality.current = e.pointerType;\n longPressEnabledOnPressStart.current = longPressEnabled;\n hadPrimaryActionOnPressStart.current = hasPrimaryAction;\n\n // Select on mouse down unless there is a primary action which will occur on mouse up.\n // For keyboard, select on key down. If there is an action, the Space key selects on key down,\n // and the Enter key performs onAction on key up.\n if (\n allowsSelection && (\n (e.pointerType === 'mouse' && !hasPrimaryAction) ||\n (e.pointerType === 'keyboard' && (!allowsActions || isSelectionKey(e.key)))\n )\n ) {\n onSelect(e);\n }\n };\n\n itemPressProps.onPress = (e) => {\n // Selection occurs on touch up. Primary actions always occur on pointer up.\n // Both primary and secondary actions occur on Enter key up. The only exception\n // is secondary actions, which occur on double click with a mouse.\n if (\n e.pointerType === 'touch' ||\n e.pointerType === 'pen' ||\n e.pointerType === 'virtual' ||\n (e.pointerType === 'keyboard' && hasAction && isActionKey(e.key)) ||\n (e.pointerType === 'mouse' && hadPrimaryActionOnPressStart.current)\n ) {\n if (hasAction) {\n performAction(e);\n } else if (allowsSelection) {\n onSelect(e);\n }\n }\n };\n }\n\n itemProps['data-collection'] = getCollectionId(manager.collection);\n itemProps['data-key'] = key;\n itemPressProps.preventFocusOnPress = shouldUseVirtualFocus;\n\n // When using virtual focus, make sure the focused key gets updated on press.\n if (shouldUseVirtualFocus) {\n itemPressProps = mergeProps(itemPressProps, {\n onPressStart(e) {\n if (e.pointerType !== 'touch') {\n manager.setFocused(true);\n manager.setFocusedKey(key);\n }\n },\n onPress(e) {\n if (e.pointerType === 'touch') {\n manager.setFocused(true);\n manager.setFocusedKey(key);\n }\n }\n });\n }\n\n if (collectionItemProps) {\n for (let key of ['onPressStart', 'onPressEnd', 'onPressChange', 'onPress', 'onPressUp', 'onClick']) {\n if (collectionItemProps[key]) {\n itemPressProps[key] = chain(itemPressProps[key], collectionItemProps[key]);\n }\n }\n }\n\n let {pressProps, isPressed} = usePress(itemPressProps);\n\n // Double clicking with a mouse with selectionBehavior = 'replace' performs an action.\n let onDoubleClick = hasSecondaryAction ? (e) => {\n if (modality.current === 'mouse') {\n e.stopPropagation();\n e.preventDefault();\n performAction(e);\n }\n } : undefined;\n\n // Long pressing an item with touch when selectionBehavior = 'replace' switches the selection behavior\n // to 'toggle'. This changes the single tap behavior from performing an action (i.e. navigating) to\n // selecting, and may toggle the appearance of a UI affordance like checkboxes on each item.\n let {longPressProps} = useLongPress({\n isDisabled: !longPressEnabled,\n onLongPress(e) {\n if (e.pointerType === 'touch') {\n onSelect(e);\n manager.setSelectionBehavior('toggle');\n }\n }\n });\n\n // Prevent native drag and drop on long press if we also select on long press.\n // Once the user is in selection mode, they can long press again to drag.\n // Use a capturing listener to ensure this runs before useDrag, regardless of\n // the order the props get merged.\n let onDragStartCapture = e => {\n if (modality.current === 'touch' && longPressEnabledOnPressStart.current) {\n e.preventDefault();\n }\n };\n\n // Prevent default on link clicks so that we control exactly\n // when they open (to match selection behavior).\n let onClick = linkBehavior !== 'none' && manager.isLink(key) ? e => {\n if (!(openLink as any).isOpening) {\n e.preventDefault();\n }\n } : undefined;\n\n return {\n itemProps: mergeProps(\n itemProps,\n allowsSelection || hasPrimaryAction || (shouldUseVirtualFocus && !isDisabled) ? pressProps : {},\n longPressEnabled ? longPressProps : {},\n {onDoubleClick, onDragStartCapture, onClick, id},\n // Prevent DOM focus from moving on mouse down when using virtual focus\n shouldUseVirtualFocus ? {onMouseDown: e => e.preventDefault()} : undefined\n ),\n isPressed,\n isSelected: manager.isSelected(key),\n isFocused: manager.isFocused && manager.focusedKey === key,\n isDisabled,\n allowsSelection,\n hasAction\n };\n}\n\nfunction isActionKey(key: string | undefined) {\n return key === 'Enter';\n}\n\nfunction isSelectionKey(key: string | undefined) {\n return key === ' ';\n}\n"],"names":[],"version":3,"file":"useSelectableItem.module.js.map"}
@@ -1,4 +1,5 @@
1
1
  var $3XJlT$react = require("react");
2
+ var $3XJlT$reactariautils = require("@react-aria/utils");
2
3
 
3
4
 
4
5
  function $parcel$export(e, n, v, s) {
@@ -17,6 +18,7 @@ $parcel$export(module.exports, "useTypeSelect", () => $a1189052f36475e8$export$e
17
18
  * OF ANY KIND, either express or implied. See the License for the specific language
18
19
  * governing permissions and limitations under the License.
19
20
  */
21
+
20
22
  /**
21
23
  * Controls how long to wait before clearing the typeahead buffer.
22
24
  */ const $a1189052f36475e8$var$TYPEAHEAD_DEBOUNCE_WAIT_MS = 1000; // 1 second
@@ -28,7 +30,7 @@ function $a1189052f36475e8$export$e32c88dfddc6e1d8(options) {
28
30
  }).current;
29
31
  let onKeyDown = (e)=>{
30
32
  let character = $a1189052f36475e8$var$getStringForKey(e.key);
31
- if (!character || e.ctrlKey || e.metaKey || !e.currentTarget.contains(e.target) || state.search.length === 0 && character === ' ') return;
33
+ if (!character || e.ctrlKey || e.metaKey || !(0, $3XJlT$reactariautils.nodeContains)(e.currentTarget, e.target) || state.search.length === 0 && character === ' ') return;
32
34
  // Do not propagate the Spacebar event if it's meant to be part of the search.
33
35
  // When we time out, the search term becomes empty, hence the check on length.
34
36
  // Trimming is to account for the case of pressing the Spacebar more than once,
@@ -1 +1 @@
1
- {"mappings":";;;;;;;;AAAA;;;;;;;;;;CAUC;AAMD;;CAEC,GACD,MAAM,mDAA6B,MAAM,WAAW;AA2B7C,SAAS,0CAAc,OAA8B;IAC1D,IAAI,oBAAC,gBAAgB,oBAAE,gBAAgB,gBAAE,YAAY,EAAC,GAAG;IACzD,IAAI,QAAQ,CAAA,GAAA,mBAAK,EAAwE;QACvF,QAAQ;QACR,SAAS;IACX,GAAG,OAAO;IAEV,IAAI,YAAY,CAAC;QACf,IAAI,YAAY,sCAAgB,EAAE,GAAG;QACrC,IAAI,CAAC,aAAa,EAAE,OAAO,IAAI,EAAE,OAAO,IAAI,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,EAAE,MAAM,KAAqB,MAAM,MAAM,CAAC,MAAM,KAAK,KAAK,cAAc,KAC5I;QAGF,8EAA8E;QAC9E,8EAA8E;QAC9E,+EAA+E;QAC/E,4EAA4E;QAC5E,IAAI,cAAc,OAAO,MAAM,MAAM,CAAC,IAAI,GAAG,MAAM,GAAG,GAAG;YACvD,EAAE,cAAc;YAChB,IAAI,CAAE,CAAA,yBAAyB,CAAA,GAC7B,EAAE,eAAe;QAErB;QAEA,MAAM,MAAM,IAAI;QAEhB,IAAI,iBAAiB,eAAe,IAAI,MAAM;YAC5C,2CAA2C;YAC3C,+FAA+F;YAC/F,IAAI,MAAM,iBAAiB,eAAe,CAAC,MAAM,MAAM,EAAE,iBAAiB,UAAU;YAEpF,wCAAwC;YACxC,IAAI,OAAO,MACT,MAAM,iBAAiB,eAAe,CAAC,MAAM,MAAM;YAGrD,IAAI,OAAO,MAAM;gBACf,iBAAiB,aAAa,CAAC;gBAC/B,IAAI,cACF,aAAa;YAEjB;QACF;QAEA,aAAa,MAAM,OAAO;QAC1B,MAAM,OAAO,GAAG,WAAW;YACzB,MAAM,MAAM,GAAG;QACjB,GAAG;IACL;IAEA,OAAO;QACL,iBAAiB;YACf,+DAA+D;YAC/D,qDAAqD;YACrD,kBAAkB,iBAAiB,eAAe,GAAG,YAAY;QACnE;IACF;AACF;AAEA,SAAS,sCAAgB,GAAW;IAClC,mDAAmD;IACnD,+DAA+D;IAC/D,6BAA6B;IAC7B,0CAA0C;IAC1C,IAAI,IAAI,MAAM,KAAK,KAAK,CAAC,UAAU,IAAI,CAAC,MACtC,OAAO;IAGT,OAAO;AACT","sources":["packages/@react-aria/selection/src/useTypeSelect.ts"],"sourcesContent":["/*\n * Copyright 2020 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 {DOMAttributes, Key, KeyboardDelegate} from '@react-types/shared';\nimport {KeyboardEvent, useRef} from 'react';\nimport {MultipleSelectionManager} from '@react-stately/selection';\n\n/**\n * Controls how long to wait before clearing the typeahead buffer.\n */\nconst TYPEAHEAD_DEBOUNCE_WAIT_MS = 1000; // 1 second\n\nexport interface AriaTypeSelectOptions {\n /**\n * A delegate that returns collection item keys with respect to visual layout.\n */\n keyboardDelegate: KeyboardDelegate,\n /**\n * An interface for reading and updating multiple selection state.\n */\n selectionManager: MultipleSelectionManager,\n /**\n * Called when an item is focused by typing.\n */\n onTypeSelect?: (key: Key) => void\n}\n\nexport interface TypeSelectAria {\n /**\n * Props to be spread on the owner of the options.\n */\n typeSelectProps: DOMAttributes\n}\n\n/**\n * Handles typeahead interactions with collections.\n */\nexport function useTypeSelect(options: AriaTypeSelectOptions): TypeSelectAria {\n let {keyboardDelegate, selectionManager, onTypeSelect} = options;\n let state = useRef<{search: string, timeout: ReturnType<typeof setTimeout> | undefined}>({\n search: '',\n timeout: undefined\n }).current;\n\n let onKeyDown = (e: KeyboardEvent) => {\n let character = getStringForKey(e.key);\n if (!character || e.ctrlKey || e.metaKey || !e.currentTarget.contains(e.target as HTMLElement) || (state.search.length === 0 && character === ' ')) {\n return;\n }\n\n // Do not propagate the Spacebar event if it's meant to be part of the search.\n // When we time out, the search term becomes empty, hence the check on length.\n // Trimming is to account for the case of pressing the Spacebar more than once,\n // which should cycle through the selection/deselection of the focused item.\n if (character === ' ' && state.search.trim().length > 0) {\n e.preventDefault();\n if (!('continuePropagation' in e)) {\n e.stopPropagation();\n }\n }\n\n state.search += character;\n\n if (keyboardDelegate.getKeyForSearch != null) {\n // Use the delegate to find a key to focus.\n // Prioritize items after the currently focused item, falling back to searching the whole list.\n let key = keyboardDelegate.getKeyForSearch(state.search, selectionManager.focusedKey);\n\n // If no key found, search from the top.\n if (key == null) {\n key = keyboardDelegate.getKeyForSearch(state.search);\n }\n\n if (key != null) {\n selectionManager.setFocusedKey(key);\n if (onTypeSelect) {\n onTypeSelect(key);\n }\n }\n }\n\n clearTimeout(state.timeout);\n state.timeout = setTimeout(() => {\n state.search = '';\n }, TYPEAHEAD_DEBOUNCE_WAIT_MS);\n };\n\n return {\n typeSelectProps: {\n // Using a capturing listener to catch the keydown event before\n // other hooks in order to handle the Spacebar event.\n onKeyDownCapture: keyboardDelegate.getKeyForSearch ? onKeyDown : undefined\n }\n };\n}\n\nfunction getStringForKey(key: string) {\n // If the key is of length 1, it is an ASCII value.\n // Otherwise, if there are no ASCII characters in the key name,\n // it is a Unicode character.\n // See https://www.w3.org/TR/uievents-key/\n if (key.length === 1 || !/^[A-Z]/i.test(key)) {\n return key;\n }\n\n return '';\n}\n"],"names":[],"version":3,"file":"useTypeSelect.main.js.map"}
1
+ {"mappings":";;;;;;;;;AAAA;;;;;;;;;;CAUC;;AAOD;;CAEC,GACD,MAAM,mDAA6B,MAAM,WAAW;AA2B7C,SAAS,0CAAc,OAA8B;IAC1D,IAAI,oBAAC,gBAAgB,oBAAE,gBAAgB,gBAAE,YAAY,EAAC,GAAG;IACzD,IAAI,QAAQ,CAAA,GAAA,mBAAK,EAAwE;QACvF,QAAQ;QACR,SAAS;IACX,GAAG,OAAO;IAEV,IAAI,YAAY,CAAC;QACf,IAAI,YAAY,sCAAgB,EAAE,GAAG;QACrC,IAAI,CAAC,aAAa,EAAE,OAAO,IAAI,EAAE,OAAO,IAAI,CAAC,CAAA,GAAA,kCAAW,EAAE,EAAE,aAAa,EAAE,EAAE,MAAM,KAAqB,MAAM,MAAM,CAAC,MAAM,KAAK,KAAK,cAAc,KACjJ;QAGF,8EAA8E;QAC9E,8EAA8E;QAC9E,+EAA+E;QAC/E,4EAA4E;QAC5E,IAAI,cAAc,OAAO,MAAM,MAAM,CAAC,IAAI,GAAG,MAAM,GAAG,GAAG;YACvD,EAAE,cAAc;YAChB,IAAI,CAAE,CAAA,yBAAyB,CAAA,GAC7B,EAAE,eAAe;QAErB;QAEA,MAAM,MAAM,IAAI;QAEhB,IAAI,iBAAiB,eAAe,IAAI,MAAM;YAC5C,2CAA2C;YAC3C,+FAA+F;YAC/F,IAAI,MAAM,iBAAiB,eAAe,CAAC,MAAM,MAAM,EAAE,iBAAiB,UAAU;YAEpF,wCAAwC;YACxC,IAAI,OAAO,MACT,MAAM,iBAAiB,eAAe,CAAC,MAAM,MAAM;YAGrD,IAAI,OAAO,MAAM;gBACf,iBAAiB,aAAa,CAAC;gBAC/B,IAAI,cACF,aAAa;YAEjB;QACF;QAEA,aAAa,MAAM,OAAO;QAC1B,MAAM,OAAO,GAAG,WAAW;YACzB,MAAM,MAAM,GAAG;QACjB,GAAG;IACL;IAEA,OAAO;QACL,iBAAiB;YACf,+DAA+D;YAC/D,qDAAqD;YACrD,kBAAkB,iBAAiB,eAAe,GAAG,YAAY;QACnE;IACF;AACF;AAEA,SAAS,sCAAgB,GAAW;IAClC,mDAAmD;IACnD,+DAA+D;IAC/D,6BAA6B;IAC7B,0CAA0C;IAC1C,IAAI,IAAI,MAAM,KAAK,KAAK,CAAC,UAAU,IAAI,CAAC,MACtC,OAAO;IAGT,OAAO;AACT","sources":["packages/@react-aria/selection/src/useTypeSelect.ts"],"sourcesContent":["/*\n * Copyright 2020 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 {DOMAttributes, Key, KeyboardDelegate} from '@react-types/shared';\nimport {KeyboardEvent, useRef} from 'react';\nimport {MultipleSelectionManager} from '@react-stately/selection';\nimport {nodeContains} from '@react-aria/utils';\n\n/**\n * Controls how long to wait before clearing the typeahead buffer.\n */\nconst TYPEAHEAD_DEBOUNCE_WAIT_MS = 1000; // 1 second\n\nexport interface AriaTypeSelectOptions {\n /**\n * A delegate that returns collection item keys with respect to visual layout.\n */\n keyboardDelegate: KeyboardDelegate,\n /**\n * An interface for reading and updating multiple selection state.\n */\n selectionManager: MultipleSelectionManager,\n /**\n * Called when an item is focused by typing.\n */\n onTypeSelect?: (key: Key) => void\n}\n\nexport interface TypeSelectAria {\n /**\n * Props to be spread on the owner of the options.\n */\n typeSelectProps: DOMAttributes\n}\n\n/**\n * Handles typeahead interactions with collections.\n */\nexport function useTypeSelect(options: AriaTypeSelectOptions): TypeSelectAria {\n let {keyboardDelegate, selectionManager, onTypeSelect} = options;\n let state = useRef<{search: string, timeout: ReturnType<typeof setTimeout> | undefined}>({\n search: '',\n timeout: undefined\n }).current;\n\n let onKeyDown = (e: KeyboardEvent) => {\n let character = getStringForKey(e.key);\n if (!character || e.ctrlKey || e.metaKey || !nodeContains(e.currentTarget, e.target as HTMLElement) || (state.search.length === 0 && character === ' ')) {\n return;\n }\n\n // Do not propagate the Spacebar event if it's meant to be part of the search.\n // When we time out, the search term becomes empty, hence the check on length.\n // Trimming is to account for the case of pressing the Spacebar more than once,\n // which should cycle through the selection/deselection of the focused item.\n if (character === ' ' && state.search.trim().length > 0) {\n e.preventDefault();\n if (!('continuePropagation' in e)) {\n e.stopPropagation();\n }\n }\n\n state.search += character;\n\n if (keyboardDelegate.getKeyForSearch != null) {\n // Use the delegate to find a key to focus.\n // Prioritize items after the currently focused item, falling back to searching the whole list.\n let key = keyboardDelegate.getKeyForSearch(state.search, selectionManager.focusedKey);\n\n // If no key found, search from the top.\n if (key == null) {\n key = keyboardDelegate.getKeyForSearch(state.search);\n }\n\n if (key != null) {\n selectionManager.setFocusedKey(key);\n if (onTypeSelect) {\n onTypeSelect(key);\n }\n }\n }\n\n clearTimeout(state.timeout);\n state.timeout = setTimeout(() => {\n state.search = '';\n }, TYPEAHEAD_DEBOUNCE_WAIT_MS);\n };\n\n return {\n typeSelectProps: {\n // Using a capturing listener to catch the keydown event before\n // other hooks in order to handle the Spacebar event.\n onKeyDownCapture: keyboardDelegate.getKeyForSearch ? onKeyDown : undefined\n }\n };\n}\n\nfunction getStringForKey(key: string) {\n // If the key is of length 1, it is an ASCII value.\n // Otherwise, if there are no ASCII characters in the key name,\n // it is a Unicode character.\n // See https://www.w3.org/TR/uievents-key/\n if (key.length === 1 || !/^[A-Z]/i.test(key)) {\n return key;\n }\n\n return '';\n}\n"],"names":[],"version":3,"file":"useTypeSelect.main.js.map"}
@@ -1,4 +1,5 @@
1
1
  import {useRef as $dAE4Y$useRef} from "react";
2
+ import {nodeContains as $dAE4Y$nodeContains} from "@react-aria/utils";
2
3
 
3
4
  /*
4
5
  * Copyright 2020 Adobe. All rights reserved.
@@ -11,6 +12,7 @@ import {useRef as $dAE4Y$useRef} from "react";
11
12
  * OF ANY KIND, either express or implied. See the License for the specific language
12
13
  * governing permissions and limitations under the License.
13
14
  */
15
+
14
16
  /**
15
17
  * Controls how long to wait before clearing the typeahead buffer.
16
18
  */ const $fb3050f43d946246$var$TYPEAHEAD_DEBOUNCE_WAIT_MS = 1000; // 1 second
@@ -22,7 +24,7 @@ function $fb3050f43d946246$export$e32c88dfddc6e1d8(options) {
22
24
  }).current;
23
25
  let onKeyDown = (e)=>{
24
26
  let character = $fb3050f43d946246$var$getStringForKey(e.key);
25
- if (!character || e.ctrlKey || e.metaKey || !e.currentTarget.contains(e.target) || state.search.length === 0 && character === ' ') return;
27
+ if (!character || e.ctrlKey || e.metaKey || !(0, $dAE4Y$nodeContains)(e.currentTarget, e.target) || state.search.length === 0 && character === ' ') return;
26
28
  // Do not propagate the Spacebar event if it's meant to be part of the search.
27
29
  // When we time out, the search term becomes empty, hence the check on length.
28
30
  // Trimming is to account for the case of pressing the Spacebar more than once,
@@ -1,4 +1,5 @@
1
1
  import {useRef as $dAE4Y$useRef} from "react";
2
+ import {nodeContains as $dAE4Y$nodeContains} from "@react-aria/utils";
2
3
 
3
4
  /*
4
5
  * Copyright 2020 Adobe. All rights reserved.
@@ -11,6 +12,7 @@ import {useRef as $dAE4Y$useRef} from "react";
11
12
  * OF ANY KIND, either express or implied. See the License for the specific language
12
13
  * governing permissions and limitations under the License.
13
14
  */
15
+
14
16
  /**
15
17
  * Controls how long to wait before clearing the typeahead buffer.
16
18
  */ const $fb3050f43d946246$var$TYPEAHEAD_DEBOUNCE_WAIT_MS = 1000; // 1 second
@@ -22,7 +24,7 @@ function $fb3050f43d946246$export$e32c88dfddc6e1d8(options) {
22
24
  }).current;
23
25
  let onKeyDown = (e)=>{
24
26
  let character = $fb3050f43d946246$var$getStringForKey(e.key);
25
- if (!character || e.ctrlKey || e.metaKey || !e.currentTarget.contains(e.target) || state.search.length === 0 && character === ' ') return;
27
+ if (!character || e.ctrlKey || e.metaKey || !(0, $dAE4Y$nodeContains)(e.currentTarget, e.target) || state.search.length === 0 && character === ' ') return;
26
28
  // Do not propagate the Spacebar event if it's meant to be part of the search.
27
29
  // When we time out, the search term becomes empty, hence the check on length.
28
30
  // Trimming is to account for the case of pressing the Spacebar more than once,
@@ -1 +1 @@
1
- {"mappings":";;AAAA;;;;;;;;;;CAUC;AAMD;;CAEC,GACD,MAAM,mDAA6B,MAAM,WAAW;AA2B7C,SAAS,0CAAc,OAA8B;IAC1D,IAAI,oBAAC,gBAAgB,oBAAE,gBAAgB,gBAAE,YAAY,EAAC,GAAG;IACzD,IAAI,QAAQ,CAAA,GAAA,aAAK,EAAwE;QACvF,QAAQ;QACR,SAAS;IACX,GAAG,OAAO;IAEV,IAAI,YAAY,CAAC;QACf,IAAI,YAAY,sCAAgB,EAAE,GAAG;QACrC,IAAI,CAAC,aAAa,EAAE,OAAO,IAAI,EAAE,OAAO,IAAI,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,EAAE,MAAM,KAAqB,MAAM,MAAM,CAAC,MAAM,KAAK,KAAK,cAAc,KAC5I;QAGF,8EAA8E;QAC9E,8EAA8E;QAC9E,+EAA+E;QAC/E,4EAA4E;QAC5E,IAAI,cAAc,OAAO,MAAM,MAAM,CAAC,IAAI,GAAG,MAAM,GAAG,GAAG;YACvD,EAAE,cAAc;YAChB,IAAI,CAAE,CAAA,yBAAyB,CAAA,GAC7B,EAAE,eAAe;QAErB;QAEA,MAAM,MAAM,IAAI;QAEhB,IAAI,iBAAiB,eAAe,IAAI,MAAM;YAC5C,2CAA2C;YAC3C,+FAA+F;YAC/F,IAAI,MAAM,iBAAiB,eAAe,CAAC,MAAM,MAAM,EAAE,iBAAiB,UAAU;YAEpF,wCAAwC;YACxC,IAAI,OAAO,MACT,MAAM,iBAAiB,eAAe,CAAC,MAAM,MAAM;YAGrD,IAAI,OAAO,MAAM;gBACf,iBAAiB,aAAa,CAAC;gBAC/B,IAAI,cACF,aAAa;YAEjB;QACF;QAEA,aAAa,MAAM,OAAO;QAC1B,MAAM,OAAO,GAAG,WAAW;YACzB,MAAM,MAAM,GAAG;QACjB,GAAG;IACL;IAEA,OAAO;QACL,iBAAiB;YACf,+DAA+D;YAC/D,qDAAqD;YACrD,kBAAkB,iBAAiB,eAAe,GAAG,YAAY;QACnE;IACF;AACF;AAEA,SAAS,sCAAgB,GAAW;IAClC,mDAAmD;IACnD,+DAA+D;IAC/D,6BAA6B;IAC7B,0CAA0C;IAC1C,IAAI,IAAI,MAAM,KAAK,KAAK,CAAC,UAAU,IAAI,CAAC,MACtC,OAAO;IAGT,OAAO;AACT","sources":["packages/@react-aria/selection/src/useTypeSelect.ts"],"sourcesContent":["/*\n * Copyright 2020 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 {DOMAttributes, Key, KeyboardDelegate} from '@react-types/shared';\nimport {KeyboardEvent, useRef} from 'react';\nimport {MultipleSelectionManager} from '@react-stately/selection';\n\n/**\n * Controls how long to wait before clearing the typeahead buffer.\n */\nconst TYPEAHEAD_DEBOUNCE_WAIT_MS = 1000; // 1 second\n\nexport interface AriaTypeSelectOptions {\n /**\n * A delegate that returns collection item keys with respect to visual layout.\n */\n keyboardDelegate: KeyboardDelegate,\n /**\n * An interface for reading and updating multiple selection state.\n */\n selectionManager: MultipleSelectionManager,\n /**\n * Called when an item is focused by typing.\n */\n onTypeSelect?: (key: Key) => void\n}\n\nexport interface TypeSelectAria {\n /**\n * Props to be spread on the owner of the options.\n */\n typeSelectProps: DOMAttributes\n}\n\n/**\n * Handles typeahead interactions with collections.\n */\nexport function useTypeSelect(options: AriaTypeSelectOptions): TypeSelectAria {\n let {keyboardDelegate, selectionManager, onTypeSelect} = options;\n let state = useRef<{search: string, timeout: ReturnType<typeof setTimeout> | undefined}>({\n search: '',\n timeout: undefined\n }).current;\n\n let onKeyDown = (e: KeyboardEvent) => {\n let character = getStringForKey(e.key);\n if (!character || e.ctrlKey || e.metaKey || !e.currentTarget.contains(e.target as HTMLElement) || (state.search.length === 0 && character === ' ')) {\n return;\n }\n\n // Do not propagate the Spacebar event if it's meant to be part of the search.\n // When we time out, the search term becomes empty, hence the check on length.\n // Trimming is to account for the case of pressing the Spacebar more than once,\n // which should cycle through the selection/deselection of the focused item.\n if (character === ' ' && state.search.trim().length > 0) {\n e.preventDefault();\n if (!('continuePropagation' in e)) {\n e.stopPropagation();\n }\n }\n\n state.search += character;\n\n if (keyboardDelegate.getKeyForSearch != null) {\n // Use the delegate to find a key to focus.\n // Prioritize items after the currently focused item, falling back to searching the whole list.\n let key = keyboardDelegate.getKeyForSearch(state.search, selectionManager.focusedKey);\n\n // If no key found, search from the top.\n if (key == null) {\n key = keyboardDelegate.getKeyForSearch(state.search);\n }\n\n if (key != null) {\n selectionManager.setFocusedKey(key);\n if (onTypeSelect) {\n onTypeSelect(key);\n }\n }\n }\n\n clearTimeout(state.timeout);\n state.timeout = setTimeout(() => {\n state.search = '';\n }, TYPEAHEAD_DEBOUNCE_WAIT_MS);\n };\n\n return {\n typeSelectProps: {\n // Using a capturing listener to catch the keydown event before\n // other hooks in order to handle the Spacebar event.\n onKeyDownCapture: keyboardDelegate.getKeyForSearch ? onKeyDown : undefined\n }\n };\n}\n\nfunction getStringForKey(key: string) {\n // If the key is of length 1, it is an ASCII value.\n // Otherwise, if there are no ASCII characters in the key name,\n // it is a Unicode character.\n // See https://www.w3.org/TR/uievents-key/\n if (key.length === 1 || !/^[A-Z]/i.test(key)) {\n return key;\n }\n\n return '';\n}\n"],"names":[],"version":3,"file":"useTypeSelect.module.js.map"}
1
+ {"mappings":";;;AAAA;;;;;;;;;;CAUC;;AAOD;;CAEC,GACD,MAAM,mDAA6B,MAAM,WAAW;AA2B7C,SAAS,0CAAc,OAA8B;IAC1D,IAAI,oBAAC,gBAAgB,oBAAE,gBAAgB,gBAAE,YAAY,EAAC,GAAG;IACzD,IAAI,QAAQ,CAAA,GAAA,aAAK,EAAwE;QACvF,QAAQ;QACR,SAAS;IACX,GAAG,OAAO;IAEV,IAAI,YAAY,CAAC;QACf,IAAI,YAAY,sCAAgB,EAAE,GAAG;QACrC,IAAI,CAAC,aAAa,EAAE,OAAO,IAAI,EAAE,OAAO,IAAI,CAAC,CAAA,GAAA,mBAAW,EAAE,EAAE,aAAa,EAAE,EAAE,MAAM,KAAqB,MAAM,MAAM,CAAC,MAAM,KAAK,KAAK,cAAc,KACjJ;QAGF,8EAA8E;QAC9E,8EAA8E;QAC9E,+EAA+E;QAC/E,4EAA4E;QAC5E,IAAI,cAAc,OAAO,MAAM,MAAM,CAAC,IAAI,GAAG,MAAM,GAAG,GAAG;YACvD,EAAE,cAAc;YAChB,IAAI,CAAE,CAAA,yBAAyB,CAAA,GAC7B,EAAE,eAAe;QAErB;QAEA,MAAM,MAAM,IAAI;QAEhB,IAAI,iBAAiB,eAAe,IAAI,MAAM;YAC5C,2CAA2C;YAC3C,+FAA+F;YAC/F,IAAI,MAAM,iBAAiB,eAAe,CAAC,MAAM,MAAM,EAAE,iBAAiB,UAAU;YAEpF,wCAAwC;YACxC,IAAI,OAAO,MACT,MAAM,iBAAiB,eAAe,CAAC,MAAM,MAAM;YAGrD,IAAI,OAAO,MAAM;gBACf,iBAAiB,aAAa,CAAC;gBAC/B,IAAI,cACF,aAAa;YAEjB;QACF;QAEA,aAAa,MAAM,OAAO;QAC1B,MAAM,OAAO,GAAG,WAAW;YACzB,MAAM,MAAM,GAAG;QACjB,GAAG;IACL;IAEA,OAAO;QACL,iBAAiB;YACf,+DAA+D;YAC/D,qDAAqD;YACrD,kBAAkB,iBAAiB,eAAe,GAAG,YAAY;QACnE;IACF;AACF;AAEA,SAAS,sCAAgB,GAAW;IAClC,mDAAmD;IACnD,+DAA+D;IAC/D,6BAA6B;IAC7B,0CAA0C;IAC1C,IAAI,IAAI,MAAM,KAAK,KAAK,CAAC,UAAU,IAAI,CAAC,MACtC,OAAO;IAGT,OAAO;AACT","sources":["packages/@react-aria/selection/src/useTypeSelect.ts"],"sourcesContent":["/*\n * Copyright 2020 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 {DOMAttributes, Key, KeyboardDelegate} from '@react-types/shared';\nimport {KeyboardEvent, useRef} from 'react';\nimport {MultipleSelectionManager} from '@react-stately/selection';\nimport {nodeContains} from '@react-aria/utils';\n\n/**\n * Controls how long to wait before clearing the typeahead buffer.\n */\nconst TYPEAHEAD_DEBOUNCE_WAIT_MS = 1000; // 1 second\n\nexport interface AriaTypeSelectOptions {\n /**\n * A delegate that returns collection item keys with respect to visual layout.\n */\n keyboardDelegate: KeyboardDelegate,\n /**\n * An interface for reading and updating multiple selection state.\n */\n selectionManager: MultipleSelectionManager,\n /**\n * Called when an item is focused by typing.\n */\n onTypeSelect?: (key: Key) => void\n}\n\nexport interface TypeSelectAria {\n /**\n * Props to be spread on the owner of the options.\n */\n typeSelectProps: DOMAttributes\n}\n\n/**\n * Handles typeahead interactions with collections.\n */\nexport function useTypeSelect(options: AriaTypeSelectOptions): TypeSelectAria {\n let {keyboardDelegate, selectionManager, onTypeSelect} = options;\n let state = useRef<{search: string, timeout: ReturnType<typeof setTimeout> | undefined}>({\n search: '',\n timeout: undefined\n }).current;\n\n let onKeyDown = (e: KeyboardEvent) => {\n let character = getStringForKey(e.key);\n if (!character || e.ctrlKey || e.metaKey || !nodeContains(e.currentTarget, e.target as HTMLElement) || (state.search.length === 0 && character === ' ')) {\n return;\n }\n\n // Do not propagate the Spacebar event if it's meant to be part of the search.\n // When we time out, the search term becomes empty, hence the check on length.\n // Trimming is to account for the case of pressing the Spacebar more than once,\n // which should cycle through the selection/deselection of the focused item.\n if (character === ' ' && state.search.trim().length > 0) {\n e.preventDefault();\n if (!('continuePropagation' in e)) {\n e.stopPropagation();\n }\n }\n\n state.search += character;\n\n if (keyboardDelegate.getKeyForSearch != null) {\n // Use the delegate to find a key to focus.\n // Prioritize items after the currently focused item, falling back to searching the whole list.\n let key = keyboardDelegate.getKeyForSearch(state.search, selectionManager.focusedKey);\n\n // If no key found, search from the top.\n if (key == null) {\n key = keyboardDelegate.getKeyForSearch(state.search);\n }\n\n if (key != null) {\n selectionManager.setFocusedKey(key);\n if (onTypeSelect) {\n onTypeSelect(key);\n }\n }\n }\n\n clearTimeout(state.timeout);\n state.timeout = setTimeout(() => {\n state.search = '';\n }, TYPEAHEAD_DEBOUNCE_WAIT_MS);\n };\n\n return {\n typeSelectProps: {\n // Using a capturing listener to catch the keydown event before\n // other hooks in order to handle the Spacebar event.\n onKeyDownCapture: keyboardDelegate.getKeyForSearch ? onKeyDown : undefined\n }\n };\n}\n\nfunction getStringForKey(key: string) {\n // If the key is of length 1, it is an ASCII value.\n // Otherwise, if there are no ASCII characters in the key name,\n // it is a Unicode character.\n // See https://www.w3.org/TR/uievents-key/\n if (key.length === 1 || !/^[A-Z]/i.test(key)) {\n return key;\n }\n\n return '';\n}\n"],"names":[],"version":3,"file":"useTypeSelect.module.js.map"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-aria/selection",
3
- "version": "3.26.0",
3
+ "version": "3.27.1",
4
4
  "description": "Spectrum UI components in React",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/main.js",
@@ -26,12 +26,12 @@
26
26
  "url": "https://github.com/adobe/react-spectrum"
27
27
  },
28
28
  "dependencies": {
29
- "@react-aria/focus": "^3.21.2",
30
- "@react-aria/i18n": "^3.12.13",
31
- "@react-aria/interactions": "^3.25.6",
32
- "@react-aria/utils": "^3.31.0",
33
- "@react-stately/selection": "^3.20.6",
34
- "@react-types/shared": "^3.32.1",
29
+ "@react-aria/focus": "^3.21.4",
30
+ "@react-aria/i18n": "^3.12.15",
31
+ "@react-aria/interactions": "^3.27.0",
32
+ "@react-aria/utils": "^3.33.0",
33
+ "@react-stately/selection": "^3.20.8",
34
+ "@react-types/shared": "^3.33.0",
35
35
  "@swc/helpers": "^0.5.0"
36
36
  },
37
37
  "peerDependencies": {
@@ -41,5 +41,5 @@
41
41
  "publishConfig": {
42
42
  "access": "public"
43
43
  },
44
- "gitHead": "0bda51183baa23306342af32a82012ea0fe0f2dc"
44
+ "gitHead": "66e51757606b43a89ed02c574ca24517323a2ab9"
45
45
  }
@@ -10,7 +10,7 @@
10
10
  * governing permissions and limitations under the License.
11
11
  */
12
12
 
13
- import {CLEAR_FOCUS_EVENT, FOCUS_EVENT, focusWithoutScrolling, getActiveElement, isCtrlKeyPressed, mergeProps, scrollIntoView, scrollIntoViewport, useEffectEvent, useEvent, useRouter, useUpdateLayoutEffect} from '@react-aria/utils';
13
+ import {CLEAR_FOCUS_EVENT, FOCUS_EVENT, focusWithoutScrolling, getActiveElement, isCtrlKeyPressed, isTabbable, mergeProps, nodeContains, scrollIntoView, scrollIntoViewport, useEvent, useRouter, useUpdateLayoutEffect} from '@react-aria/utils';
14
14
  import {dispatchVirtualFocus, getFocusableTreeWalker, moveVirtualFocus} from '@react-aria/focus';
15
15
  import {DOMAttributes, FocusableElement, FocusStrategy, Key, KeyboardDelegate, RefObject} from '@react-types/shared';
16
16
  import {flushSync} from 'react-dom';
@@ -118,7 +118,6 @@ export function useSelectableCollection(options: AriaSelectableCollectionOptions
118
118
  disallowTypeAhead = false,
119
119
  shouldUseVirtualFocus,
120
120
  allowsTabNavigation = false,
121
- isVirtualized,
122
121
  // If no scrollRef is provided, assume the collection ref is the scrollable region
123
122
  scrollRef = ref,
124
123
  linkBehavior = 'action'
@@ -134,7 +133,7 @@ export function useSelectableCollection(options: AriaSelectableCollectionOptions
134
133
 
135
134
  // Keyboard events bubble through portals. Don't handle keyboard events
136
135
  // for elements outside the collection (e.g. menus).
137
- if (!ref.current?.contains(e.target as Element)) {
136
+ if (!ref.current || !nodeContains(ref.current, e.target as Element)) {
138
137
  return;
139
138
  }
140
139
 
@@ -312,7 +311,10 @@ export function useSelectableCollection(options: AriaSelectableCollectionOptions
312
311
  }
313
312
  } while (last);
314
313
 
315
- if (next && !next.contains(document.activeElement)) {
314
+ // If the active element is NOT tabbable but is contained by an element that IS tabbable (aka the cell), the browser will actually move focus to
315
+ // the containing element. We need to special case this so that tab will move focus out of the grid instead of looping between
316
+ // focusing the containing cell and back to the non-tabbable child element
317
+ if (next && (!nodeContains(next, document.activeElement) || (document.activeElement && !isTabbable(document.activeElement)))) {
316
318
  focusWithoutScrolling(next);
317
319
  }
318
320
  }
@@ -325,7 +327,7 @@ export function useSelectableCollection(options: AriaSelectableCollectionOptions
325
327
  // Store the scroll position so we can restore it later.
326
328
  /// TODO: should this happen all the time??
327
329
  let scrollPos = useRef({top: 0, left: 0});
328
- useEvent(scrollRef, 'scroll', isVirtualized ? undefined : () => {
330
+ useEvent(scrollRef, 'scroll', () => {
329
331
  scrollPos.current = {
330
332
  top: scrollRef.current?.scrollTop ?? 0,
331
333
  left: scrollRef.current?.scrollLeft ?? 0
@@ -335,7 +337,7 @@ export function useSelectableCollection(options: AriaSelectableCollectionOptions
335
337
  let onFocus = (e: FocusEvent) => {
336
338
  if (manager.isFocused) {
337
339
  // If a focus event bubbled through a portal, reset focus state.
338
- if (!e.currentTarget.contains(e.target)) {
340
+ if (!nodeContains(e.currentTarget, e.target)) {
339
341
  manager.setFocused(false);
340
342
  }
341
343
 
@@ -343,7 +345,7 @@ export function useSelectableCollection(options: AriaSelectableCollectionOptions
343
345
  }
344
346
 
345
347
  // Focus events can bubble through portals. Ignore these events.
346
- if (!e.currentTarget.contains(e.target)) {
348
+ if (!nodeContains(e.currentTarget, e.target)) {
347
349
  return;
348
350
  }
349
351
 
@@ -366,7 +368,7 @@ export function useSelectableCollection(options: AriaSelectableCollectionOptions
366
368
  } else {
367
369
  navigateToKey(manager.firstSelectedKey ?? delegate.getFirstKey?.());
368
370
  }
369
- } else if (!isVirtualized && scrollRef.current) {
371
+ } else if (scrollRef.current) {
370
372
  // Restore the scroll position to what it was before.
371
373
  scrollRef.current.scrollTop = scrollPos.current.top;
372
374
  scrollRef.current.scrollLeft = scrollPos.current.left;
@@ -377,7 +379,7 @@ export function useSelectableCollection(options: AriaSelectableCollectionOptions
377
379
  let element = getItemElement(ref, manager.focusedKey);
378
380
  if (element instanceof HTMLElement) {
379
381
  // This prevents a flash of focus on the first/last element in the collection, or the collection itself.
380
- if (!element.contains(document.activeElement) && !shouldUseVirtualFocus) {
382
+ if (!nodeContains(element, document.activeElement) && !shouldUseVirtualFocus) {
381
383
  focusWithoutScrolling(element);
382
384
  }
383
385
 
@@ -391,7 +393,7 @@ export function useSelectableCollection(options: AriaSelectableCollectionOptions
391
393
 
392
394
  let onBlur = (e) => {
393
395
  // Don't set blurred and then focused again if moving focus within the collection.
394
- if (!e.currentTarget.contains(e.relatedTarget as HTMLElement)) {
396
+ if (!nodeContains(e.currentTarget, e.relatedTarget as HTMLElement)) {
395
397
  manager.setFocused(false);
396
398
  }
397
399
  };
@@ -413,49 +415,42 @@ export function useSelectableCollection(options: AriaSelectableCollectionOptions
413
415
  }
414
416
  });
415
417
 
416
- let updateActiveDescendant = useEffectEvent(() => {
417
- let keyToFocus = delegate.getFirstKey?.() ?? null;
418
-
419
- // If no focusable items exist in the list, make sure to clear any activedescendant that may still exist and move focus back to
420
- // the original active element (e.g. the autocomplete input)
421
- if (keyToFocus == null) {
422
- let previousActiveElement = getActiveElement();
423
- moveVirtualFocus(ref.current);
424
- dispatchVirtualFocus(previousActiveElement!, null);
425
-
426
- // If there wasn't a focusable key but the collection had items, then that means we aren't in an intermediate load state and all keys are disabled.
427
- // Reset shouldVirtualFocusFirst so that we don't erronously autofocus an item when the collection is filtered again.
428
- if (manager.collection.size > 0) {
418
+ // update active descendant
419
+ useUpdateLayoutEffect(() => {
420
+ if (shouldVirtualFocusFirst.current) {
421
+ let keyToFocus = delegate.getFirstKey?.() ?? null;
422
+
423
+ // If no focusable items exist in the list, make sure to clear any activedescendant that may still exist and move focus back to
424
+ // the original active element (e.g. the autocomplete input)
425
+ if (keyToFocus == null) {
426
+ let previousActiveElement = getActiveElement();
427
+ moveVirtualFocus(ref.current);
428
+ dispatchVirtualFocus(previousActiveElement!, null);
429
+
430
+ // If there wasn't a focusable key but the collection had items, then that means we aren't in an intermediate load state and all keys are disabled.
431
+ // Reset shouldVirtualFocusFirst so that we don't erronously autofocus an item when the collection is filtered again.
432
+ if (manager.collection.size > 0) {
433
+ shouldVirtualFocusFirst.current = false;
434
+ }
435
+ } else {
436
+ manager.setFocusedKey(keyToFocus);
437
+ // Only set shouldVirtualFocusFirst to false if we've successfully set the first key as the focused key
438
+ // If there wasn't a key to focus, we might be in a temporary loading state so we'll want to still focus the first key
439
+ // after the collection updates after load
429
440
  shouldVirtualFocusFirst.current = false;
430
441
  }
431
- } else {
432
- manager.setFocusedKey(keyToFocus);
433
- // Only set shouldVirtualFocusFirst to false if we've successfully set the first key as the focused key
434
- // If there wasn't a key to focus, we might be in a temporary loading state so we'll want to still focus the first key
435
- // after the collection updates after load
436
- shouldVirtualFocusFirst.current = false;
437
442
  }
438
- });
443
+ }, [manager.collection]);
439
444
 
445
+ // reset focus first flag
440
446
  useUpdateLayoutEffect(() => {
441
- if (shouldVirtualFocusFirst.current) {
442
- updateActiveDescendant();
443
- }
444
-
445
- }, [manager.collection, updateActiveDescendant]);
446
-
447
- let resetFocusFirstFlag = useEffectEvent(() => {
448
447
  // If user causes the focused key to change in any other way, clear shouldVirtualFocusFirst so we don't
449
448
  // accidentally move focus from under them. Skip this if the collection was empty because we might be in a load
450
449
  // state and will still want to focus the first item after load
451
450
  if (manager.collection.size > 0) {
452
451
  shouldVirtualFocusFirst.current = false;
453
452
  }
454
- });
455
-
456
- useUpdateLayoutEffect(() => {
457
- resetFocusFirstFlag();
458
- }, [manager.focusedKey, resetFocusFirstFlag]);
453
+ }, [manager.focusedKey]);
459
454
 
460
455
  useEvent(ref, CLEAR_FOCUS_EVENT, !shouldUseVirtualFocus ? undefined : (e: any) => {
461
456
  e.stopPropagation();
@@ -200,6 +200,12 @@ export function useSelectableItem(options: SelectableItemOptions): SelectableIte
200
200
  };
201
201
  }
202
202
 
203
+ useEffect(() => {
204
+ if (isDisabled && manager.focusedKey === key) {
205
+ manager.setFocusedKey(null);
206
+ }
207
+ }, [manager, isDisabled, key]);
208
+
203
209
  // With checkbox selection, onAction (i.e. navigation) becomes primary, and occurs on a single click of the row.
204
210
  // Clicking the checkbox enters selection mode, after which clicking anywhere on any row toggles selection for that row.
205
211
  // With highlight selection, onAction is secondary, and occurs on double click. Single click selects the row.
@@ -246,7 +252,7 @@ export function useSelectableItem(options: SelectableItemOptions): SelectableIte
246
252
  itemPressProps.onPressStart = (e) => {
247
253
  modality.current = e.pointerType;
248
254
  longPressEnabledOnPressStart.current = longPressEnabled;
249
- if (e.pointerType === 'keyboard' && (!hasAction || isSelectionKey())) {
255
+ if (e.pointerType === 'keyboard' && (!hasAction || isSelectionKey(e.key))) {
250
256
  onSelect(e);
251
257
  }
252
258
  };
@@ -256,7 +262,7 @@ export function useSelectableItem(options: SelectableItemOptions): SelectableIte
256
262
  if (!allowsDifferentPressOrigin) {
257
263
  itemPressProps.onPress = (e) => {
258
264
  if (hasPrimaryAction || (hasSecondaryAction && e.pointerType !== 'mouse')) {
259
- if (e.pointerType === 'keyboard' && !isActionKey()) {
265
+ if (e.pointerType === 'keyboard' && !isActionKey(e.key)) {
260
266
  return;
261
267
  }
262
268
 
@@ -290,7 +296,7 @@ export function useSelectableItem(options: SelectableItemOptions): SelectableIte
290
296
  if (
291
297
  allowsSelection && (
292
298
  (e.pointerType === 'mouse' && !hasPrimaryAction) ||
293
- (e.pointerType === 'keyboard' && (!allowsActions || isSelectionKey()))
299
+ (e.pointerType === 'keyboard' && (!allowsActions || isSelectionKey(e.key)))
294
300
  )
295
301
  ) {
296
302
  onSelect(e);
@@ -305,7 +311,7 @@ export function useSelectableItem(options: SelectableItemOptions): SelectableIte
305
311
  e.pointerType === 'touch' ||
306
312
  e.pointerType === 'pen' ||
307
313
  e.pointerType === 'virtual' ||
308
- (e.pointerType === 'keyboard' && hasAction && isActionKey()) ||
314
+ (e.pointerType === 'keyboard' && hasAction && isActionKey(e.key)) ||
309
315
  (e.pointerType === 'mouse' && hadPrimaryActionOnPressStart.current)
310
316
  ) {
311
317
  if (hasAction) {
@@ -407,12 +413,10 @@ export function useSelectableItem(options: SelectableItemOptions): SelectableIte
407
413
  };
408
414
  }
409
415
 
410
- function isActionKey() {
411
- let event = window.event as KeyboardEvent;
412
- return event?.key === 'Enter';
416
+ function isActionKey(key: string | undefined) {
417
+ return key === 'Enter';
413
418
  }
414
419
 
415
- function isSelectionKey() {
416
- let event = window.event as KeyboardEvent;
417
- return event?.key === ' ' || event?.code === 'Space';
420
+ function isSelectionKey(key: string | undefined) {
421
+ return key === ' ';
418
422
  }
@@ -13,6 +13,7 @@
13
13
  import {DOMAttributes, Key, KeyboardDelegate} from '@react-types/shared';
14
14
  import {KeyboardEvent, useRef} from 'react';
15
15
  import {MultipleSelectionManager} from '@react-stately/selection';
16
+ import {nodeContains} from '@react-aria/utils';
16
17
 
17
18
  /**
18
19
  * Controls how long to wait before clearing the typeahead buffer.
@@ -53,7 +54,7 @@ export function useTypeSelect(options: AriaTypeSelectOptions): TypeSelectAria {
53
54
 
54
55
  let onKeyDown = (e: KeyboardEvent) => {
55
56
  let character = getStringForKey(e.key);
56
- if (!character || e.ctrlKey || e.metaKey || !e.currentTarget.contains(e.target as HTMLElement) || (state.search.length === 0 && character === ' ')) {
57
+ if (!character || e.ctrlKey || e.metaKey || !nodeContains(e.currentTarget, e.target as HTMLElement) || (state.search.length === 0 && character === ' ')) {
57
58
  return;
58
59
  }
59
60