fix: harden hierarchy keys and virtual navigation
This commit is contained in:
+21
-5
@@ -35,13 +35,20 @@
|
||||
return rows.find((row) => row && row.key === key) || null;
|
||||
}
|
||||
|
||||
function expansionState(state) {
|
||||
return state.searchQuery && state.searchExpandedKeys instanceof Set
|
||||
? { field: 'searchExpandedKeys', keys: state.searchExpandedKeys }
|
||||
: { field: 'expandedKeys', keys: state.expandedKeys };
|
||||
}
|
||||
|
||||
function changeExpansion(state, row, force) {
|
||||
if (!row || row.kind === 'camera') return state;
|
||||
const expandedKeys = copySet(state.expandedKeys);
|
||||
const current = expansionState(state);
|
||||
const expandedKeys = copySet(current.keys);
|
||||
const shouldExpand = force === undefined ? !expandedKeys.has(row.key) : force;
|
||||
if (shouldExpand) expandedKeys.add(row.key);
|
||||
else expandedKeys.delete(row.key);
|
||||
return Object.assign({}, state, { expandedKeys, activeKey: row.key });
|
||||
return Object.assign({}, state, { [current.field]: expandedKeys, activeKey: row.key });
|
||||
}
|
||||
|
||||
function activate(state, row) {
|
||||
@@ -101,8 +108,13 @@
|
||||
}
|
||||
if (!rows.length) return state;
|
||||
let index = rows.findIndex((row) => row.key === state.activeKey);
|
||||
if (index < 0) index = 0;
|
||||
if (index < 0) {
|
||||
if (action.key === 'ArrowDown' || action.key === 'Home') return moveActive(state, rows, 0);
|
||||
if (action.key === 'ArrowUp' || action.key === 'End') return moveActive(state, rows, rows.length - 1);
|
||||
index = 0;
|
||||
}
|
||||
const row = rows[index];
|
||||
const expandedKeys = expansionState(state).keys;
|
||||
switch (action.key) {
|
||||
case 'ArrowDown': return moveActive(state, rows, index + 1);
|
||||
case 'ArrowUp': return moveActive(state, rows, index - 1);
|
||||
@@ -110,12 +122,12 @@
|
||||
case 'End': return moveActive(state, rows, rows.length - 1);
|
||||
case 'ArrowRight': {
|
||||
if (row.kind === 'camera') return state;
|
||||
if (!state.expandedKeys.has(row.key)) return changeExpansion(state, row, true);
|
||||
if (!expandedKeys.has(row.key)) return changeExpansion(state, row, true);
|
||||
const child = rows[index + 1];
|
||||
return child && child.parentKey === row.key ? Object.assign({}, state, { activeKey: child.key }) : state;
|
||||
}
|
||||
case 'ArrowLeft':
|
||||
if (row.kind !== 'camera' && state.expandedKeys.has(row.key)) return changeExpansion(state, row, false);
|
||||
if (row.kind !== 'camera' && expandedKeys.has(row.key)) return changeExpansion(state, row, false);
|
||||
return row.parentKey && validKey(row.parentKey) ? Object.assign({}, state, { activeKey: row.parentKey }) : state;
|
||||
case 'Enter':
|
||||
case ' ':
|
||||
@@ -150,6 +162,10 @@
|
||||
matchCameraKeys: state.searchQuery ? state.searchCameraKeys : null,
|
||||
});
|
||||
const activeIndex = rows.findIndex((row) => row.key === state.activeKey);
|
||||
const maximumScrollTop = Math.max(0, (rows.length * rowHeight) - state.viewportHeight);
|
||||
if (state.scrollTop > maximumScrollTop) {
|
||||
state = Object.assign({}, state, { scrollTop: maximumScrollTop });
|
||||
}
|
||||
if (activeIndex >= 0 && state.viewportHeight > 0) {
|
||||
const activeTop = activeIndex * rowHeight;
|
||||
const activeBottom = activeTop + rowHeight;
|
||||
|
||||
Reference in New Issue
Block a user