@nature-ui/clickable
Version:
React hook and component that implements native button interactions
146 lines (144 loc) • 3.85 kB
JavaScript
// src/use-clickable.tsx
import { dataAttr, mergeRefs } from "@nature-ui/utils";
import React from "react";
var useClickable = (props = {}) => {
const {
ref: htmlRef,
isDisabled,
isFocusable,
clickOnEnter = true,
clickOnSpace = true,
onMouseDown,
onMouseUp,
onClick,
onKeyDown,
onKeyUp,
tabIndex: tabIndexProp,
onMouseOver,
...htmlProps
} = props;
const [isButton, setIsButton] = React.useState(true);
const [isActive, setIsActive] = React.useState(false);
const refCallback = React.useCallback((node) => {
if ((node == null ? void 0 : node.tagName) !== "BUTTON") {
setIsButton(false);
}
}, []);
const tabIndex = isButton ? tabIndexProp : tabIndexProp || 0;
const trulyDisabled = isDisabled && !isFocusable;
const handleClick = React.useCallback(
(event) => {
if (isDisabled) {
event.stopPropagation();
event.preventDefault();
return;
}
const selft = event.currentTarget;
selft.focus();
onClick == null ? void 0 : onClick(event);
},
[isDisabled, onClick]
);
const handleKeyDown = React.useCallback(
(event) => {
onKeyDown == null ? void 0 : onKeyDown(event);
if (isDisabled || event.defaultPrevented || event.metaKey) {
return;
}
const shouldClickOnEnter = clickOnEnter && event.key === "Enter";
const shouldClickOnSpace = clickOnSpace && event.key === " ";
if (!isButton && shouldClickOnSpace) {
event.preventDefault();
setIsActive(true);
return;
}
if (!isButton && shouldClickOnEnter) {
event.preventDefault();
const self = event.currentTarget;
self.click();
}
},
[isDisabled, isButton, onKeyDown, clickOnEnter, clickOnSpace]
);
const handleKeyUp = React.useCallback(
(event) => {
onKeyUp == null ? void 0 : onKeyUp(event);
if (isDisabled || event.defaultPrevented || event.metaKey)
return;
const shouldClickOnSpace = clickOnSpace && event.key === " ";
if (!isButton && shouldClickOnSpace) {
event.preventDefault();
setIsActive(false);
const self = event.currentTarget;
self.click();
}
},
[clickOnSpace, isButton, isDisabled, onKeyUp]
);
const handleMouseDown = React.useCallback(
(event) => {
if (isDisabled) {
event.stopPropagation();
event.preventDefault();
return;
}
if (!isButton) {
setIsActive(true);
}
onMouseDown == null ? void 0 : onMouseDown(event);
},
[isDisabled, isButton, onMouseDown]
);
const handleMouseUp = React.useCallback(
(event) => {
if (!isButton) {
setIsActive(false);
}
onMouseUp == null ? void 0 : onMouseUp(event);
},
[onMouseUp, isButton]
);
const handleMouseOver = React.useCallback(
(event) => {
if (isDisabled) {
event.preventDefault();
return;
}
onMouseOver == null ? void 0 : onMouseOver(event);
},
[isDisabled, onMouseOver]
);
const ref = mergeRefs(htmlRef, refCallback);
if (isButton) {
return {
...htmlProps,
ref,
type: "button",
"aria-disabled": trulyDisabled ? void 0 : isDisabled,
disabled: trulyDisabled,
onClick: handleClick,
onMouseDown,
onMouseUp,
onKeyUp,
onKeyDown,
onMouseOver
};
}
return {
...htmlProps,
ref,
role: "button",
"data-active": dataAttr(isActive),
"aria-disabled": Boolean(isDisabled),
tabIndex: trulyDisabled ? void 0 : tabIndex,
onClick: handleClick,
onMouseDown: handleMouseDown,
onMouseUp: handleMouseUp,
onKeyUp: handleKeyUp,
onKeyDown: handleKeyDown,
onMouseOver: handleMouseOver
};
};
export {
useClickable
};