UNPKG

react-aria

Version:
1 lines • 17.6 kB
{"mappings":"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","sources":["packages/react-aria/src/grid/useGridCell.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, FocusableElement, Key, RefObject} from '@react-types/shared';\nimport {focusSafely} from '../interactions/focusSafely';\nimport {\n getActiveElement,\n getEventTarget,\n isFocusWithin,\n nodeContains\n} from '../utils/shadowdom/DOMFunctions';\nimport {getFocusableTreeWalker} from '../focus/FocusScope';\nimport {getScrollParent} from '../utils/getScrollParent';\nimport {\n IGridCollection as GridCollection,\n GridNode\n} from 'react-stately/private/grid/GridCollection';\nimport {gridMap} from './utils';\nimport {GridState} from 'react-stately/private/grid/useGridState';\nimport {isFocusVisible} from '../interactions/useFocusVisible';\nimport {mergeProps} from '../utils/mergeProps';\nimport {KeyboardEvent as ReactKeyboardEvent, useRef} from 'react';\nimport {scrollIntoViewport} from '../utils/scrollIntoView';\nimport {useLocale} from '../i18n/I18nProvider';\nimport {useSelectableItem} from '../selection/useSelectableItem';\n\nexport interface GridCellProps {\n /**\n * An object representing the grid cell. Contains all the relevant information that makes up the\n * grid cell.\n */\n node: GridNode<unknown>;\n /** Whether the grid cell is contained in a virtual scroller. */\n isVirtualized?: boolean;\n /**\n * Whether the cell or its first focusable child element should be focused when the grid cell is\n * focused.\n */\n focusMode?: 'child' | 'cell';\n /** Whether selection should occur on press up instead of press down. */\n shouldSelectOnPressUp?: boolean;\n /** Indicates how many columns the data cell spans. */\n colSpan?: number;\n /**\n * Handler that is called when a user performs an action on the cell.\n * Please use onCellAction at the collection level instead.\n *\n * @deprecated\n */\n onAction?: () => void;\n}\n\nexport interface GridCellAria {\n /** Props for the grid cell element. */\n gridCellProps: DOMAttributes;\n /** Whether the cell is currently in a pressed state. */\n isPressed: boolean;\n}\n\n/**\n * Provides the behavior and accessibility implementation for a cell in a grid.\n *\n * @param props - Props for the cell.\n * @param state - State of the parent grid, as returned by `useGridState`.\n */\nexport function useGridCell<T, C extends GridCollection<T>>(\n props: GridCellProps,\n state: GridState<T, C>,\n ref: RefObject<FocusableElement | null>\n): GridCellAria {\n let {node, isVirtualized, focusMode = 'child', shouldSelectOnPressUp, onAction} = props;\n\n let {direction} = useLocale();\n let {\n keyboardDelegate,\n actions: {onCellAction}\n } = gridMap.get(state)!;\n\n // We need to track the key of the item at the time it was last focused so that we force\n // focus to go to the item when the DOM node is reused for a different item in a virtualizer.\n let keyWhenFocused = useRef<Key | null>(null);\n\n // Handles focusing the cell. If there is a focusable child,\n // it is focused, otherwise the cell itself is focused.\n let focus = () => {\n if (ref.current) {\n let treeWalker = getFocusableTreeWalker(ref.current);\n if (focusMode === 'child') {\n // If focus is already on a focusable child within the cell, early return so we don't shift focus\n if (isFocusWithin(ref.current) && ref.current !== getActiveElement()) {\n return;\n }\n\n let focusable =\n state.selectionManager.childFocusStrategy === 'last'\n ? last(treeWalker)\n : (treeWalker.firstChild() as FocusableElement);\n if (focusable) {\n focusSafely(focusable);\n return;\n }\n }\n\n if (\n (keyWhenFocused.current != null && node.key !== keyWhenFocused.current) ||\n !isFocusWithin(ref.current)\n ) {\n focusSafely(ref.current);\n }\n }\n };\n\n let {itemProps, isPressed} = useSelectableItem({\n selectionManager: state.selectionManager,\n key: node.key,\n ref,\n isVirtualized,\n focus,\n shouldSelectOnPressUp,\n onAction: onCellAction ? () => onCellAction(node.key) : onAction,\n isDisabled: state.collection.size === 0\n });\n\n let onKeyDownCapture = (e: ReactKeyboardEvent) => {\n let activeElement = getActiveElement();\n if (\n !nodeContains(e.currentTarget, getEventTarget(e) as Element) ||\n state.isKeyboardNavigationDisabled ||\n !ref.current ||\n !activeElement\n ) {\n return;\n }\n\n let walker = getFocusableTreeWalker(ref.current);\n walker.currentNode = activeElement;\n\n switch (e.key) {\n case 'ArrowLeft': {\n // Find the next focusable element within the cell.\n let focusable: FocusableElement | null =\n direction === 'rtl'\n ? (walker.nextNode() as FocusableElement)\n : (walker.previousNode() as FocusableElement);\n\n // Don't focus the cell itself if focusMode is \"child\"\n if (focusMode === 'child' && focusable === ref.current) {\n focusable = null;\n }\n\n e.preventDefault();\n e.stopPropagation();\n if (focusable) {\n focusSafely(focusable);\n scrollIntoViewport(focusable, {containingElement: getScrollParent(ref.current)});\n } else {\n // If there is no next focusable child, then move to the next cell to the left of this one.\n // This will be handled by useSelectableCollection. However, if there is no cell to the left\n // of this one, only one column, and the grid doesn't focus rows, then the next key will be the\n // same as this one. In that case we need to handle focusing either the cell or the first/last\n // child, depending on the focus mode.\n let prev = keyboardDelegate.getKeyLeftOf?.(node.key);\n if (prev !== node.key) {\n // We prevent the capturing event from reaching children of the cell, e.g. pickers.\n // We want arrow keys to navigate to the next cell instead. We need to re-dispatch\n // the event from a higher parent so it still bubbles and gets handled by useSelectableCollection.\n ref.current.parentElement?.dispatchEvent(\n new KeyboardEvent(e.nativeEvent.type, e.nativeEvent)\n );\n break;\n }\n\n if (focusMode === 'cell' && direction === 'rtl') {\n focusSafely(ref.current);\n scrollIntoViewport(ref.current, {containingElement: getScrollParent(ref.current)});\n } else {\n walker.currentNode = ref.current;\n focusable =\n direction === 'rtl' ? (walker.firstChild() as FocusableElement) : last(walker);\n if (focusable) {\n focusSafely(focusable);\n scrollIntoViewport(focusable, {containingElement: getScrollParent(ref.current)});\n }\n }\n }\n break;\n }\n case 'ArrowRight': {\n let focusable: FocusableElement | null =\n direction === 'rtl'\n ? (walker.previousNode() as FocusableElement)\n : (walker.nextNode() as FocusableElement);\n\n if (focusMode === 'child' && focusable === ref.current) {\n focusable = null;\n }\n\n e.preventDefault();\n e.stopPropagation();\n if (focusable) {\n focusSafely(focusable);\n scrollIntoViewport(focusable, {containingElement: getScrollParent(ref.current)});\n } else {\n let next = keyboardDelegate.getKeyRightOf?.(node.key);\n if (next !== node.key) {\n // We prevent the capturing event from reaching children of the cell, e.g. pickers.\n // We want arrow keys to navigate to the next cell instead. We need to re-dispatch\n // the event from a higher parent so it still bubbles and gets handled by useSelectableCollection.\n ref.current.parentElement?.dispatchEvent(\n new KeyboardEvent(e.nativeEvent.type, e.nativeEvent)\n );\n break;\n }\n\n if (focusMode === 'cell' && direction === 'ltr') {\n focusSafely(ref.current);\n scrollIntoViewport(ref.current, {containingElement: getScrollParent(ref.current)});\n } else {\n walker.currentNode = ref.current;\n focusable =\n direction === 'rtl' ? last(walker) : (walker.firstChild() as FocusableElement);\n if (focusable) {\n focusSafely(focusable);\n scrollIntoViewport(focusable, {containingElement: getScrollParent(ref.current)});\n }\n }\n }\n break;\n }\n case 'ArrowUp':\n case 'ArrowDown':\n // Prevent this event from reaching cell children, e.g. menu buttons. We want arrow keys to navigate\n // to the cell above/below instead. We need to re-dispatch the event from a higher parent so it still\n // bubbles and gets handled by useSelectableCollection.\n if (!e.altKey && nodeContains(ref.current, getEventTarget(e) as Element)) {\n e.stopPropagation();\n e.preventDefault();\n ref.current.parentElement?.dispatchEvent(\n new KeyboardEvent(e.nativeEvent.type, e.nativeEvent)\n );\n }\n break;\n }\n };\n\n // Grid cells can have focusable elements inside them. In this case, focus should\n // be marshalled to that element rather than focusing the cell itself.\n let onFocus = e => {\n keyWhenFocused.current = node.key;\n if (getEventTarget(e) !== ref.current) {\n // useSelectableItem only handles setting the focused key when\n // the focused element is the gridcell itself. We also want to\n // set the focused key when a child element receives focus.\n // If focus is currently visible (e.g. the user is navigating with the keyboard),\n // then skip this. We want to restore focus to the previously focused row/cell\n // in that case since the table should act like a single tab stop.\n if (!isFocusVisible()) {\n state.selectionManager.setFocusedKey(node.key);\n }\n return;\n }\n\n // If the cell itself is focused, wait a frame so that focus finishes propagatating\n // up to the tree, and move focus to a focusable child if possible.\n requestAnimationFrame(() => {\n if (focusMode === 'child' && getActiveElement() === ref.current) {\n focus();\n }\n });\n };\n\n let gridCellProps: DOMAttributes = mergeProps(itemProps, {\n role: 'gridcell',\n onKeyDownCapture,\n 'aria-colspan': node.colSpan,\n 'aria-colindex': node.colIndex != null ? node.colIndex + 1 : undefined, // aria-colindex is 1-based\n colSpan: isVirtualized ? undefined : node.colSpan,\n onFocus\n });\n\n if (isVirtualized) {\n gridCellProps['aria-colindex'] = (node.colIndex ?? node.index) + 1; // aria-colindex is 1-based\n }\n\n // When pressing with a pointer and cell selection is not enabled, usePress will be applied to the\n // row rather than the cell. However, when the row is draggable, usePress cannot preventDefault\n // on pointer down, so the browser will try to focus the cell which has a tabIndex applied.\n // To avoid this, remove the tabIndex from the cell briefly on pointer down.\n if (\n shouldSelectOnPressUp &&\n gridCellProps.tabIndex != null &&\n gridCellProps.onPointerDown == null\n ) {\n gridCellProps.onPointerDown = e => {\n let el = e.currentTarget;\n let tabindex = el.getAttribute('tabindex');\n el.removeAttribute('tabindex');\n requestAnimationFrame(() => {\n if (tabindex != null) {\n el.setAttribute('tabindex', tabindex);\n }\n });\n };\n }\n\n return {\n gridCellProps,\n isPressed\n };\n}\n\nfunction last(walker: TreeWalker) {\n let next: FocusableElement | null = null;\n let last: FocusableElement | null = null;\n do {\n last = walker.lastChild() as FocusableElement | null;\n if (last) {\n next = last;\n }\n } while (last);\n return next;\n}\n"],"names":[],"version":3,"file":"useGridCell.cjs.map"}