UNPKG

@carbon/ibm-products

Version:

Carbon for IBM Products

106 lines (100 loc) 4.25 kB
/** * Copyright IBM Corp. 2020, 2025 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ 'use strict'; var React = require('react'); var handleMultipleKeys = require('../utils/handleMultipleKeys.js'); var usePreviousValue = require('../../../global/js/hooks/usePreviousValue.js'); const hasFocus = () => typeof document !== 'undefined' && document.hasFocus(); const useMultipleKeyTracking = _ref => { let { ref, containerHasFocus, isEditing } = _ref; const [usingMac, setUsingMac] = React.useState(''); const [windowFocused, setWindowFocused] = React.useState(hasFocus); const [keysPressedList, setKeysPressedList] = React.useState([]); const previousState = usePreviousValue.usePreviousValue({ isEditing, windowFocused, containerHasFocus }); // useEffect to check for window focus, if window loses focus // we need to clear out the keysPressedList React.useEffect(() => { const userAgentString = window.navigator.userAgent; if (userAgentString.includes('Macintosh')) { setUsingMac(true); } else { setUsingMac(false); } setWindowFocused(hasFocus()); const onWindowFocus = () => setWindowFocused(true); const onWindowBlur = () => setWindowFocused(false); window.addEventListener('focus', onWindowFocus); window.addEventListener('blur', onWindowBlur); return () => { window.removeEventListener('focus', onWindowFocus); window.removeEventListener('blur', onWindowBlur); }; }, []); React.useEffect(() => { if (ref && containerHasFocus && !isEditing) { ref.current.onkeydown = ref.current.onkeyup = event => { // If keydown, we will add the new key to the keysPressedList array if (event.type === 'keydown') { // Prevent multiple keys of the same type being added to our keysPressedList array if (keysPressedList.includes(event.code)) { return; } // Because keyup events are lost when using the Command key // we need to remove the previously pressed keys so that we // do not have keys in the pressed list that should not be if (handleMultipleKeys.includesResourceKey(keysPressedList, usingMac) && keysPressedList.length > 1) { const clonedKeys = [...keysPressedList]; const filteredClonedKeys = clonedKeys.filter(item => item === 'MetaLeft' || item === 'MetaRight'); filteredClonedKeys.push(event.code); return setKeysPressedList([...new Set(filteredClonedKeys)]); } const tempKeys = [...keysPressedList]; tempKeys.push(event.code); setKeysPressedList([...new Set(tempKeys)]); } // If keyup, we will remove the key from the keysPressedList array if (event.type === 'keyup') { const tempKeys = [...keysPressedList]; const filteredClone = tempKeys.filter(item => item !== event.code); // Keyup events are lost on all other keys if a Meta key is used // so to work around this behavior, we empty out all other keys // from the keysPressedList array if we detect a Meta keyup event if (event.code === 'MetaLeft' || event.code === 'MetaRight') { return setKeysPressedList([]); } setKeysPressedList([...new Set(filteredClone)]); } }; } if (previousState?.windowFocused && !windowFocused) { setKeysPressedList([]); } // Remove handlers if the spreadsheet container loses focus // or is currently in edit mode if (ref && !containerHasFocus || isEditing) { ref.current.onkeydown = undefined; ref.current.onkeyup = undefined; if (!previousState?.isEditing && isEditing || previousState?.containerHasFocus && !containerHasFocus) { setKeysPressedList([]); } } }, [keysPressedList, containerHasFocus, ref, isEditing, previousState?.isEditing, previousState?.containerHasFocus, windowFocused, previousState?.windowFocused, usingMac]); return { keysPressedList, windowFocused, usingMac }; }; exports.useMultipleKeyTracking = useMultipleKeyTracking;