@smart-react-components/ui
Version:
SRC UI includes React and Styled components.
130 lines (129 loc) • 5.03 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const useChangeEffect_1 = __importDefault(require("@smart-react-components/core/hooks/useChangeEffect"));
const react_1 = require("react");
const useSelectBoxHover = ({ active, children, dropdownStatus, hasHover, isDisabled, setActive, setDropdownStatus }) => {
const [hovered, setHovered] = (0, react_1.useState)(undefined);
/**
* Finds the hovered JSX element based on the value.
* Pushes the parents to the path array.
*/
const findHoveredChild = (parent, path) => {
let children;
if (Array.isArray(parent)) {
children = parent;
}
else {
children = Array.isArray(parent.props.children) ? parent.props.children : [parent.props.children];
}
for (let i = 0; i < children.length; i++) {
const child = children[i];
switch (child.type.displayName) {
case 'Option':
if (child.props.value === hovered) {
return child;
}
break;
case 'OptionGroup':
path.push(child);
const hoveredChild = findHoveredChild(child, path);
if (hoveredChild) {
return hoveredChild;
}
path.pop();
break;
}
}
return null;
};
/**
* Finds the next hovered JSX element based on the current hovered element and direction.
*/
const findNextHoveredChild = (child, path, direction, skipIncrease = false) => {
if (path.length === 0) {
return null;
}
const parent = path.pop();
let children;
if (Array.isArray(parent)) {
children = parent;
}
else {
children = Array.isArray(parent.props.children) ? parent.props.children : [parent.props.children];
}
let idx = children.findIndex(i => i === child) + (skipIncrease ? 0 : direction);
while (idx >= 0 && idx < children.length) {
const child = children[idx];
switch (child.type.displayName) {
case 'Option':
if (!child.props.isDisabled && ![null, undefined].includes(child.props.value)) {
return child;
}
break;
case 'OptionGroup':
path.push(child);
const nextChildCandidate = Array.isArray(child.props.children)
? direction === 1 ? child.props.children[0] : child.props.children[child.props.children.length - 1]
: child.props.children;
const nextChild = findNextHoveredChild(nextChildCandidate, path, direction, true);
if (nextChild) {
return nextChild;
}
path.pop();
break;
}
idx += direction;
}
// Array means that parent is root, so no need to go further since the root cannot have more parents.
if (Array.isArray(parent)) {
return null;
}
return findNextHoveredChild(parent, path, direction);
};
const handleKeyDown = (e) => {
if (['ArrowDown', 'ArrowUp'].includes(e.key)) {
const hoveredChildPath = [children];
const currentChild = findHoveredChild(children, hoveredChildPath);
const nextChild = findNextHoveredChild(currentChild, hoveredChildPath, e.key === 'ArrowDown' ? 1 : -1);
if (nextChild) {
setHovered(nextChild.props.value);
}
e.preventDefault();
}
if (e.key === 'Enter' && hovered !== undefined) {
if (!Array.isArray(active)) {
setDropdownStatus(false);
setActive(hovered);
}
else {
if (!active.includes(hovered)) {
setActive([...active, hovered]);
}
else {
setActive(active.filter(i => i !== hovered));
}
}
}
};
(0, useChangeEffect_1.default)(() => {
if (dropdownStatus) {
setHovered(undefined);
}
}, [dropdownStatus]);
(0, useChangeEffect_1.default)(() => {
if (hasHover && dropdownStatus && !isDisabled) {
window.addEventListener('keydown', handleKeyDown);
return () => {
window.removeEventListener('keydown', handleKeyDown);
};
}
}, [dropdownStatus, hasHover, hovered, isDisabled]);
return {
hovered,
setHovered,
};
};
exports.default = useSelectBoxHover;
;