react-aria
Version:
Spectrum UI components in React
1 lines • 23.2 kB
Source Map (JSON)
{"mappings":"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","sources":["packages/react-aria/src/selection/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} from '../utils/chain';\n\nimport {\n DOMAttributes,\n DOMProps,\n FocusableElement,\n Key,\n LongPressEvent,\n PointerType,\n PressEvent,\n RefObject\n} from '@react-types/shared';\nimport {focusSafely} from '../interactions/focusSafely';\nimport {getActiveElement, getEventTarget} from '../utils/shadowdom/DOMFunctions';\nimport {getCollectionId, isNonContiguousSelectionModifier} from './utils';\nimport {isCtrlKeyPressed} from '../utils/keyboard';\nimport {mergeProps} from '../utils/mergeProps';\nimport {moveVirtualFocus} from '../focus/virtualFocus';\nimport {MultipleSelectionManager} from 'react-stately/useMultipleSelectionState';\nimport {openLink, useRouter} from '../utils/openLink';\nimport {PressHookProps, usePress} from '../interactions/usePress';\nimport {useEffect, useRef} from 'react';\nimport {useId} from '../utils/useId';\nimport {useLongPress} from '../interactions/useLongPress';\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\n * triggers selection on 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\n * on 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 *\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\n * may 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\n * `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 (\n manager.selectionBehavior === 'toggle' ||\n (e && (isCtrlKeyPressed(e) || e.pointerType === 'touch' || e.pointerType === 'virtual'))\n ) {\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 (getActiveElement() !== 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 }, [\n ref,\n key,\n manager.focusedKey,\n manager.childFocusStrategy,\n manager.isFocused,\n shouldUseVirtualFocus\n ]);\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 (getEventTarget(e) === 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 =\n manager.isLink(key) && linkBehavior !== 'selection' && linkBehavior !== 'none';\n let allowsSelection =\n !isDisabled && manager.canSelectItem(key) && !isLinkOverride && !isActionOverride;\n let allowsActions = (onAction || hasLinkAction) && !isDisabled;\n let hasPrimaryAction =\n allowsActions &&\n (manager.selectionBehavior === 'replace'\n ? !allowsSelection\n : !allowsSelection || manager.isEmpty);\n let hasSecondaryAction =\n 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\n ? undefined\n : e => {\n if (e.pointerType === 'mouse' && allowsSelection) {\n onSelect(e);\n }\n };\n\n itemPressProps.onPress = hasPrimaryAction\n ? performAction\n : 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 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 [\n 'onPressStart',\n 'onPressEnd',\n 'onPressChange',\n 'onPress',\n 'onPressUp',\n 'onClick'\n ]) {\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\n ? e => {\n if (modality.current === 'mouse') {\n e.stopPropagation();\n e.preventDefault();\n performAction(e);\n }\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 =\n linkBehavior !== 'none' && manager.isLink(key)\n ? e => {\n if (!(openLink as any).isOpening) {\n e.preventDefault();\n }\n }\n : undefined;\n\n return {\n itemProps: mergeProps(\n itemProps,\n allowsSelection || hasPrimaryAction || (shouldUseVirtualFocus && !isDisabled)\n ? pressProps\n : {},\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.mjs.map"}