rsuite
Version:
A suite of react components
183 lines (175 loc) • 5.37 kB
JavaScript
'use client';
import { shallowEqual } from "../../internals/utils/index.js";
// Active tree node selector
const SELECTED_TREEITEM_SELECTOR = '[role="treeitem"][aria-selected="true"]';
/**
* Retrieves the focusable items from the filtered data based on the provided props.
* Excludes nodes that are not visible or are disabled.
*/
export const getFocusableItems = (filteredData, props, isSearching) => {
const {
disabledItemValues,
valueKey,
childrenKey,
expandItemValues
} = props;
const items = [];
const loop = nodes => {
nodes.forEach(node => {
const disabled = disabledItemValues.some(disabledItem => shallowEqual(disabledItem, node[valueKey]));
if (!disabled && node.visible) {
items.push(node);
}
// always expand when searching
const expand = isSearching ? true : expandItemValues.includes(node[valueKey]);
if (node[childrenKey] && expand) {
loop(node[childrenKey]);
}
});
};
loop(filteredData);
return items;
};
/**
* Returns the index of the active item in the focusItems array.
*
*/
const getActiveIndex = (focusItemValue, focusItems, valueKey) => {
let activeIndex = -1;
focusItems.forEach((item, index) => {
if (shallowEqual(item[valueKey], focusItemValue)) {
activeIndex = index;
}
});
return activeIndex;
};
/**
* Retrieves the active item from the flattened nodes based on the provided focus item value.
*/
export const getActiveItem = (focusItemValue, flattenedNodes, valueKey) => {
let nodeData = null;
const activeNode = Object.values(flattenedNodes).find(node => shallowEqual(node[valueKey], focusItemValue));
if (activeNode) {
nodeData = activeNode;
}
return nodeData;
};
/**
* Focuses on a specific tree node element.
*
*/
export const focusTreeNode = (refKey, treeNodeRefs) => {
var _treeItem$focus;
const treeItem = treeNodeRefs[refKey];
treeItem === null || treeItem === void 0 || (_treeItem$focus = treeItem.focus) === null || _treeItem$focus === void 0 || _treeItem$focus.call(treeItem);
};
/**
* Focuses on the next item in a tree.
*/
export const focusNextItem = props => {
const {
focusItemValue,
focusableItems,
treeNodesRefs,
valueKey
} = props;
const activeIndex = getActiveIndex(focusItemValue, focusableItems, valueKey);
if (focusableItems.length === 0) {
return;
}
const nextIndex = activeIndex === focusableItems.length - 1 ? 0 : activeIndex + 1;
const value = focusableItems[nextIndex][valueKey];
focusTreeNode(focusableItems[nextIndex].refKey, treeNodesRefs);
return value;
};
/**
* Focuses on the previous item in a tree.
*/
export const focusPreviousItem = props => {
const {
focusItemValue,
focusableItems,
treeNodesRefs,
valueKey
} = props;
const activeIndex = getActiveIndex(focusItemValue, focusableItems, valueKey);
if (focusableItems.length === 0) {
return;
}
let prevIndex = activeIndex === 0 ? focusableItems.length - 1 : activeIndex - 1;
prevIndex = prevIndex >= 0 ? prevIndex : 0;
const value = focusableItems[prevIndex][valueKey];
focusTreeNode(focusableItems[prevIndex].refKey, treeNodesRefs);
return value;
};
/**
* Focuses on the first item in a tree.
*/
export const focusFirstItem = props => {
const {
focusableItems,
treeNodesRefs,
valueKey
} = props;
if (focusableItems.length === 0) {
return;
}
const firstItem = focusableItems[0];
const value = firstItem[valueKey];
focusTreeNode(firstItem.refKey, treeNodesRefs);
return value;
};
/**
* Focuses on the last item in a tree.
*/
export const focusLastItem = props => {
const {
focusableItems,
treeNodesRefs,
valueKey
} = props;
if (focusableItems.length === 0) {
return;
}
const lastItem = focusableItems[focusableItems.length - 1];
const value = lastItem[valueKey];
focusTreeNode(lastItem.refKey, treeNodesRefs);
return value;
};
/**
* Returns the index of the first visible node in the tree that matches the given value.
*/
const getScrollToIndex = (nodes, value, valueKey) => {
return nodes.filter(n => n.visible).findIndex(item => item[valueKey] === value);
};
/**
* Scrolls the list to the active tree node.
*
* @param props - The props object containing the necessary parameters.
*/
export function scrollToActiveTreeNode(props) {
const {
list,
value,
valueKey,
virtualized,
formattedNodes
} = props;
if (virtualized && value) {
var _list$scrollToItem;
const scrollIndex = getScrollToIndex(formattedNodes, value, valueKey);
list === null || list === void 0 || (_list$scrollToItem = list.scrollToItem) === null || _list$scrollToItem === void 0 || _list$scrollToItem.call(list, scrollIndex);
}
}
export const focusCurrentItem = props => {
const {
selector = SELECTED_TREEITEM_SELECTOR,
container
} = props;
const activeItem = container === null || container === void 0 ? void 0 : container.querySelector(selector);
if (activeItem) {
var _activeItem$focus, _activeItem$dataset;
activeItem === null || activeItem === void 0 || (_activeItem$focus = activeItem.focus) === null || _activeItem$focus === void 0 || _activeItem$focus.call(activeItem);
return (_activeItem$dataset = activeItem.dataset) === null || _activeItem$dataset === void 0 ? void 0 : _activeItem$dataset.key;
}
};