@gechiui/block-editor
Version:
179 lines (152 loc) • 4.45 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.useDebouncedShowMovers = useDebouncedShowMovers;
exports.useShowMoversGestures = useShowMoversGestures;
var _lodash = require("lodash");
var _element = require("@gechiui/element");
/**
* External dependencies
*/
/**
* GeChiUI dependencies
*/
const {
clearTimeout,
setTimeout
} = window;
const DEBOUNCE_TIMEOUT = 200;
/**
* Hook that creates a showMover state, as well as debounced show/hide callbacks.
*
* @param {Object} props Component props.
* @param {Object} props.ref Element reference.
* @param {boolean} props.isFocused Whether the component has current focus.
* @param {number} [props.debounceTimeout=250] Debounce timeout in milliseconds.
* @param {Function} [props.onChange=noop] Callback function.
*/
function useDebouncedShowMovers(_ref) {
let {
ref,
isFocused,
debounceTimeout = DEBOUNCE_TIMEOUT,
onChange = _lodash.noop
} = _ref;
const [showMovers, setShowMovers] = (0, _element.useState)(false);
const timeoutRef = (0, _element.useRef)();
const handleOnChange = nextIsFocused => {
if (ref !== null && ref !== void 0 && ref.current) {
setShowMovers(nextIsFocused);
}
onChange(nextIsFocused);
};
const getIsHovered = () => {
return (ref === null || ref === void 0 ? void 0 : ref.current) && ref.current.matches(':hover');
};
const shouldHideMovers = () => {
const isHovered = getIsHovered();
return !isFocused && !isHovered;
};
const clearTimeoutRef = () => {
const timeout = timeoutRef.current;
if (timeout && clearTimeout) {
clearTimeout(timeout);
}
};
const debouncedShowMovers = event => {
if (event) {
event.stopPropagation();
}
clearTimeoutRef();
if (!showMovers) {
handleOnChange(true);
}
};
const debouncedHideMovers = event => {
if (event) {
event.stopPropagation();
}
clearTimeoutRef();
timeoutRef.current = setTimeout(() => {
if (shouldHideMovers()) {
handleOnChange(false);
}
}, debounceTimeout);
};
(0, _element.useEffect)(() => () => clearTimeoutRef(), []);
return {
showMovers,
debouncedShowMovers,
debouncedHideMovers
};
}
/**
* Hook that provides a showMovers state and gesture events for DOM elements
* that interact with the showMovers state.
*
* @param {Object} props Component props.
* @param {Object} props.ref Element reference.
* @param {number} [props.debounceTimeout=250] Debounce timeout in milliseconds.
* @param {Function} [props.onChange=noop] Callback function.
*/
function useShowMoversGestures(_ref2) {
let {
ref,
debounceTimeout = DEBOUNCE_TIMEOUT,
onChange = _lodash.noop
} = _ref2;
const [isFocused, setIsFocused] = (0, _element.useState)(false);
const {
showMovers,
debouncedShowMovers,
debouncedHideMovers
} = useDebouncedShowMovers({
ref,
debounceTimeout,
isFocused,
onChange
});
const registerRef = (0, _element.useRef)(false);
const isFocusedWithin = () => {
return (ref === null || ref === void 0 ? void 0 : ref.current) && ref.current.contains(ref.current.ownerDocument.activeElement);
};
(0, _element.useEffect)(() => {
const node = ref.current;
const handleOnFocus = () => {
if (isFocusedWithin()) {
setIsFocused(true);
debouncedShowMovers();
}
};
const handleOnBlur = () => {
if (!isFocusedWithin()) {
setIsFocused(false);
debouncedHideMovers();
}
};
/**
* Events are added via DOM events (vs. React synthetic events),
* as the child React components swallow mouse events.
*/
if (node && !registerRef.current) {
node.addEventListener('focus', handleOnFocus, true);
node.addEventListener('blur', handleOnBlur, true);
registerRef.current = true;
}
return () => {
if (node) {
node.removeEventListener('focus', handleOnFocus);
node.removeEventListener('blur', handleOnBlur);
}
};
}, [ref, registerRef, setIsFocused, debouncedShowMovers, debouncedHideMovers]);
return {
showMovers,
gestures: {
onMouseMove: debouncedShowMovers,
onMouseLeave: debouncedHideMovers
}
};
}
//# sourceMappingURL=utils.js.map