UNPKG

@bianic-ui/clickable

Version:

React hook and component that implements native button interactions

170 lines (149 loc) 5.19 kB
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } import { dataAttr, isRightClick, mergeRefs } from "@bianic-ui/utils"; import { useCallback, useState } from "react"; /** * useClickable * * React hook that implements all the interactions of a native `button` * component with support for making it focusable even if it's disabled. * * It can be used with both native button elements or other elements (like `div`). */ export function useClickable(props) { if (props === void 0) { props = {}; } var { ref: htmlRef, isDisabled, isFocusable, clickOnEnter = true, clickOnSpace = true, onMouseDown, onMouseUp, onClick, onKeyDown, onKeyUp, tabIndex: tabIndexProp, onMouseOver } = props, htmlProps = _objectWithoutPropertiesLoose(props, ["ref", "isDisabled", "isFocusable", "clickOnEnter", "clickOnSpace", "onMouseDown", "onMouseUp", "onClick", "onKeyDown", "onKeyUp", "tabIndex", "onMouseOver"]); /** * We'll use this to track if the element is a button element */ var [isButton, setIsButton] = useState(true); /** * For custom button implementation, we'll use this to track when * we mouse down on the button, to enable use style it's ":active" style */ var [isActive, setIsActive] = useState(false); /** * The ref callback that fires as soon as the dom node is ready */ var refCallback = useCallback(node => { if ((node == null ? void 0 : node.tagName) !== "BUTTON") { setIsButton(false); } }, []); var tabIndex = isButton ? tabIndexProp : tabIndexProp || 0; var trulyDisabled = isDisabled && !isFocusable; var handleClick = useCallback(event => { if (isDisabled) { event.stopPropagation(); event.preventDefault(); return; } var self = event.currentTarget; self.focus(); onClick == null ? void 0 : onClick(event); }, [isDisabled, onClick]); var handleKeyDown = useCallback(event => { onKeyDown == null ? void 0 : onKeyDown(event); if (isDisabled || event.defaultPrevented || event.metaKey) { return; } var shouldClickOnEnter = clickOnEnter && event.key === "Enter"; var shouldClickOnSpace = clickOnSpace && event.key === " "; if (!isButton && shouldClickOnSpace) { event.preventDefault(); setIsActive(true); return; } if (!isButton && shouldClickOnEnter) { event.preventDefault(); var self = event.currentTarget; self.click(); return; } }, [isDisabled, isButton, onKeyDown, clickOnEnter, clickOnSpace]); var handleKeyUp = useCallback(event => { onKeyUp == null ? void 0 : onKeyUp(event); if (isDisabled || event.defaultPrevented || event.metaKey) return; var shouldClickOnSpace = clickOnSpace && event.key === " "; if (!isButton && shouldClickOnSpace) { event.preventDefault(); setIsActive(false); var self = event.currentTarget; self.click(); } }, [clickOnSpace, isButton, isDisabled, onKeyUp]); var handleMouseDown = useCallback(event => { /** * Prevent right-click from triggering the * active state. */ if (isRightClick(event)) return; if (isDisabled) { event.stopPropagation(); event.preventDefault(); return; } if (!isButton) { setIsActive(true); } onMouseDown == null ? void 0 : onMouseDown(event); }, [isDisabled, isButton, onMouseDown]); var handleMouseUp = useCallback(event => { if (!isButton) { setIsActive(false); } onMouseUp == null ? void 0 : onMouseUp(event); }, [onMouseUp, isButton]); var handleMouseOver = useCallback(event => { if (isDisabled) { event.preventDefault(); return; } onMouseOver == null ? void 0 : onMouseOver(event); }, [isDisabled, onMouseOver]); var ref = mergeRefs(htmlRef, refCallback); if (isButton) { return _extends({}, htmlProps, { ref, type: "button", "aria-disabled": trulyDisabled ? undefined : isDisabled, disabled: trulyDisabled, onClick: handleClick, onMouseDown, onMouseUp, onKeyUp, onKeyDown, onMouseOver }); } return _extends({}, htmlProps, { ref, role: "button", "data-active": dataAttr(isActive), "aria-disabled": !!isDisabled, tabIndex: trulyDisabled ? undefined : tabIndex, onClick: handleClick, onMouseDown: handleMouseDown, onMouseUp: handleMouseUp, onKeyUp: handleKeyUp, onKeyDown: handleKeyDown, onMouseOver: handleMouseOver }); } //# sourceMappingURL=use-clickable.js.map