UNPKG

@yamada-ui/use-clickable

Version:

Yamada UI useClickable custom hook

190 lines (189 loc) • 5.2 kB
"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