@yamada-ui/use-clickable
Version:
Yamada UI useClickable custom hook
190 lines (189 loc) • 5.2 kB
JavaScript
"use client"
// src/index.ts
import { useEventListeners } from "@yamada-ui/use-event-listener";
import { dataAttr, isTouchDevice, mergeRefs } from "@yamada-ui/utils";
import { useCallback, useState } from "react";
var isValidElement = (ev) => {
const { isContentEditable, tagName } = ev.target;
return tagName !== "INPUT" && tagName !== "TEXTAREA" && !isContentEditable;
};
var useClickable = ({
ref,
clickOnEnter = true,
clickOnSpace = true,
isDisabled,
disabled = isDisabled,
disableTouchBehavior = true,
isFocusable,
focusable = isFocusable,
focusOnClick = true,
tabIndex: _tabIndex,
onClick,
onKeyDown,
onKeyUp,
onMouseDown,
onMouseLeave,
onMouseOver,
onMouseUp,
...props
} = {}) => {
const [button, setButton] = useState(true);
const [pressed, setPressed] = useState(false);
const listeners = useEventListeners();
const tabIndex = button ? _tabIndex : _tabIndex || 0;
const trulyDisabled = disabled && !focusable;
const refCb = (node) => {
if (!node) return;
if (node.tagName !== "BUTTON") setButton(false);
};
const handleClick = useCallback(
(ev) => {
if (disabled) {
ev.stopPropagation();
ev.preventDefault();
return;
}
if (focusOnClick) ev.currentTarget.focus();
onClick == null ? void 0 : onClick(ev);
},
[disabled, focusOnClick, onClick]
);
const onDocumentKeyUp = useCallback(
(ev) => {
if (pressed && isValidElement(ev)) {
ev.preventDefault();
ev.stopPropagation();
setPressed(false);
listeners.remove(document, "keyup", onDocumentKeyUp, false);
}
},
[pressed, listeners]
);
const handleKeyDown = useCallback(
(ev) => {
onKeyDown == null ? void 0 : onKeyDown(ev);
if (disabled || ev.defaultPrevented || ev.metaKey) return;
if (!isValidElement(ev.nativeEvent) || button) return;
if (clickOnSpace && ev.key === " ") {
ev.preventDefault();
setPressed(true);
}
if (clickOnEnter && ev.key === "Enter") {
ev.preventDefault();
ev.currentTarget.click();
}
listeners.add(document, "keyup", onDocumentKeyUp, false);
},
[
disabled,
button,
onKeyDown,
clickOnEnter,
clickOnSpace,
listeners,
onDocumentKeyUp
]
);
const handleKeyUp = useCallback(
(ev) => {
onKeyUp == null ? void 0 : onKeyUp(ev);
if (disabled || ev.defaultPrevented || ev.metaKey) return;
if (!isValidElement(ev.nativeEvent) || button) return;
if (clickOnSpace && ev.key === " ") {
ev.preventDefault();
setPressed(false);
ev.currentTarget.click();
}
},
[clickOnSpace, button, disabled, onKeyUp]
);
const onDocumentMouseUp = useCallback(
(ev) => {
if (ev.button !== 0) return;
setPressed(false);
listeners.remove(document, "mouseup", onDocumentMouseUp, false);
},
[listeners]
);
const handleMouseDown = useCallback(
(ev) => {
if (ev.button !== 0) return;
if (disabled) {
ev.stopPropagation();
ev.preventDefault();
return;
}
if (!button) setPressed(true);
if (focusOnClick) ev.currentTarget.focus({ preventScroll: true });
listeners.add(document, "mouseup", onDocumentMouseUp, false);
onMouseDown == null ? void 0 : onMouseDown(ev);
},
[disabled, button, focusOnClick, onMouseDown, listeners, onDocumentMouseUp]
);
const handleMouseUp = useCallback(
(ev) => {
if (ev.button !== 0) return;
if (!button) setPressed(false);
onMouseUp == null ? void 0 : onMouseUp(ev);
},
[onMouseUp, button]
);
const handleMouseOver = useCallback(
(ev) => {
if (disabled) {
ev.preventDefault();
return;
}
if (disableTouchBehavior && isTouchDevice()) return;
onMouseOver == null ? void 0 : onMouseOver(ev);
},
[disabled, onMouseOver, disableTouchBehavior]
);
const handleMouseLeave = useCallback(
(ev) => {
if (pressed) {
ev.preventDefault();
setPressed(false);
}
if (disableTouchBehavior && isTouchDevice()) return;
onMouseLeave == null ? void 0 : onMouseLeave(ev);
},
[pressed, onMouseLeave, disableTouchBehavior]
);
if (button) {
return {
...props,
ref: mergeRefs(ref, refCb),
type: "button",
"aria-disabled": trulyDisabled ? void 0 : disabled,
disabled: trulyDisabled,
onClick: handleClick,
onKeyDown,
onKeyUp,
onMouseDown,
onMouseLeave,
onMouseOver,
onMouseUp
};
} else {
return {
...props,
ref: mergeRefs(ref, refCb),
"aria-disabled": disabled ? "true" : void 0,
"data-active": dataAttr(pressed),
role: "button",
tabIndex: trulyDisabled ? void 0 : tabIndex,
onClick: handleClick,
onKeyDown: handleKeyDown,
onKeyUp: handleKeyUp,
onMouseDown: handleMouseDown,
onMouseLeave: handleMouseLeave,
onMouseOver: handleMouseOver,
onMouseUp: handleMouseUp
};
}
};
export {
useClickable
};
//# sourceMappingURL=index.mjs.map