UNPKG

@hashicorp/design-system-components

Version:
253 lines (251 loc) 8.19 kB
function matchesAxis(value, axis) { // `true` matches all axes, a string value matches only that axis return value === true || value === axis; } function findEnabledItem(items, startIndex, direction, loop) { const length = items.length; if (length === 0) { return undefined; } let index = startIndex + direction; if (loop === true) { for (let step = 0; step < length; step++) { const item = items[(index % length + length) % length]; if (item.disabled === false) { return item; } index += direction; } } else { while (index >= 0 && index < length) { const item = items[index]; if (item.disabled === false) { return item; } index += direction; } } return undefined; } function findFirstEnabled(items) { return items.find(item => item.disabled === false); } function findLastEnabled(items) { for (let index = items.length - 1; index >= 0; index--) { if (items[index].disabled === false) { return items[index]; } } return undefined; } function getItemsInGroup(items, groupId) { return items.filter(item => item.groupId === groupId); } function resolveColumnTarget(targetItems, columnIndex) { if (columnIndex < 0 || columnIndex >= targetItems.length) { return findLastEnabled(targetItems); } const target = targetItems[columnIndex]; if (target.disabled === false) { return target; } return findEnabledItem(targetItems, columnIndex, 1, false) ?? findEnabledItem(targetItems, columnIndex, -1, false); } function handleKey(event, snapshot, config) { const { key, ctrlKey } = event; const hasGroups = snapshot.groups.length > 0; if (hasGroups === true && config.orientation === undefined) { return handle2DKey(key, ctrlKey, snapshot, config); } return handle1DKey(key, snapshot, config); } function handle1DKey(key, snapshot, config) { const { orientation } = config; switch (key) { case 'ArrowRight': if (orientation === 'vertical') { return undefined; } return navigateLinear(snapshot, config, 'horizontal', 1); case 'ArrowLeft': if (orientation === 'vertical') { return undefined; } return navigateLinear(snapshot, config, 'horizontal', -1); case 'ArrowDown': if (orientation === 'horizontal') { return undefined; } return navigateLinear(snapshot, config, 'vertical', 1); case 'ArrowUp': if (orientation === 'horizontal') { return undefined; } return navigateLinear(snapshot, config, 'vertical', -1); case 'Home': return findFirstEnabled(snapshot.items); case 'End': return findLastEnabled(snapshot.items); default: return undefined; } } function handle2DKey(key, ctrlKey, snapshot, config) { switch (key) { case 'ArrowRight': return navigateInRow(snapshot, config, 1); case 'ArrowLeft': return navigateInRow(snapshot, config, -1); case 'ArrowDown': return navigateColumn(snapshot, config, 1); case 'ArrowUp': return navigateColumn(snapshot, config, -1); case 'Home': if (ctrlKey === true) { return findFirstEnabled(snapshot.items); } return navigateRowEnd(snapshot, -1); case 'End': if (ctrlKey === true) { return findLastEnabled(snapshot.items); } return navigateRowEnd(snapshot, 1); case 'PageDown': return navigateColumnEnd(snapshot, 1); case 'PageUp': return navigateColumnEnd(snapshot, -1); default: return undefined; } } function navigateLinear(snapshot, config, axis, direction) { const { items, currentIndex } = snapshot; if (currentIndex === -1) { return direction === 1 ? findFirstEnabled(items) : findLastEnabled(items); } return findEnabledItem(items, currentIndex, direction, matchesAxis(config.loop, axis)); } function navigateInRow(snapshot, config, direction) { const { currentItem, items, groups } = snapshot; if (currentItem === undefined || currentItem.groupId === undefined) { return undefined; } const rowItems = getItemsInGroup(items, currentItem.groupId); const rowIndex = rowItems.findIndex(item => item.id === currentItem.id); const shouldLoop = matchesAxis(config.loop, 'horizontal'); const found = findEnabledItem(rowItems, rowIndex, direction, shouldLoop); if (found !== undefined) { return found; } if (matchesAxis(config.wrap, 'horizontal') === false) { return undefined; } const groupIndex = groups.findIndex(group => group.id === currentItem.groupId); const adjacentGroupIndex = groupIndex + direction; if (adjacentGroupIndex < 0 || adjacentGroupIndex >= groups.length) { return undefined; } const adjacentItems = getItemsInGroup(items, groups[adjacentGroupIndex].id); return direction === 1 ? findFirstEnabled(adjacentItems) : findLastEnabled(adjacentItems); } function navigateColumn(snapshot, config, direction) { const { currentItem, items, groups } = snapshot; if (currentItem === undefined || currentItem.groupId === undefined) { return undefined; } const columnIndex = getItemsInGroup(items, currentItem.groupId).findIndex(item => item.id === currentItem.id); const currentGroupIndex = groups.findIndex(group => group.id === currentItem.groupId); let targetGroupIndex = currentGroupIndex + direction; if (matchesAxis(config.loop, 'vertical') === true) { const length = groups.length; targetGroupIndex = (targetGroupIndex % length + length) % length; for (let step = 0; step < length - 1; step++) { const targetItems = getItemsInGroup(items, groups[targetGroupIndex].id); const target = resolveColumnTarget(targetItems, columnIndex); if (target !== undefined) { return target; } targetGroupIndex = ((targetGroupIndex + direction) % length + length) % length; } return undefined; } else if (targetGroupIndex < 0 || targetGroupIndex >= groups.length) { if (matchesAxis(config.wrap, 'vertical') === false) { return undefined; } let wrapGroupIndex = direction === 1 ? 0 : groups.length - 1; const nextColumnIndex = columnIndex + direction; if (nextColumnIndex < 0) { return undefined; } while (wrapGroupIndex >= 0 && wrapGroupIndex < groups.length) { const wrapItems = getItemsInGroup(items, groups[wrapGroupIndex].id); if (nextColumnIndex < wrapItems.length) { const target = resolveColumnTarget(wrapItems, nextColumnIndex); if (target !== undefined) { return target; } } wrapGroupIndex += direction; } return undefined; } while (targetGroupIndex >= 0 && targetGroupIndex < groups.length) { const targetItems = getItemsInGroup(items, groups[targetGroupIndex].id); const target = resolveColumnTarget(targetItems, columnIndex); if (target !== undefined) { return target; } targetGroupIndex += direction; } return undefined; } function navigateColumnEnd(snapshot, direction) { const { currentItem, items, groups } = snapshot; if (currentItem === undefined || currentItem.groupId === undefined) { return undefined; } const columnIndex = getItemsInGroup(items, currentItem.groupId).findIndex(item => item.id === currentItem.id); let targetGroupIndex = direction === 1 ? groups.length - 1 : 0; while (targetGroupIndex >= 0 && targetGroupIndex < groups.length) { const targetItems = getItemsInGroup(items, groups[targetGroupIndex].id); const target = resolveColumnTarget(targetItems, columnIndex); if (target !== undefined) { return target; } targetGroupIndex -= direction; } return undefined; } function navigateRowEnd(snapshot, direction) { const { currentItem, items } = snapshot; if (currentItem === undefined || currentItem.groupId === undefined) { return undefined; } const rowItems = getItemsInGroup(items, currentItem.groupId); return direction === 1 ? findLastEnabled(rowItems) : findFirstEnabled(rowItems); } export { findFirstEnabled, handleKey }; //# sourceMappingURL=navigation.js.map