Skip to content

Commit

Permalink
feat(TreeView): support additional navigation and selection behavior (c…
Browse files Browse the repository at this point in the history
…arbon-design-system#11328)

* feat(TreeView): implement `Home` and `End` key navigation

* feat(TreeView): support Shift + `Home` and `End` multiselection

* feat(match): support `event.code` matching

* feat(TreeView): add `ctrl + A` selection

* chore: add arm64 build artifacts

* fix(TreeView): update shift + home/end shortcut

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
emyarod and kodiakhq[bot] authored May 4, 2022
1 parent 56f1d5b commit 34f1309
Show file tree
Hide file tree
Showing 9 changed files with 58 additions and 3 deletions.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
43 changes: 42 additions & 1 deletion packages/react/src/components/TreeView/TreeView.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export default function TreeView({
}
);
}

function handleTreeSelect(event, node = {}) {
const { id: nodeId } = node;
if (multiselect && (event.metaKey || event.ctrlKey)) {
Expand All @@ -56,6 +57,7 @@ export default function TreeView({
}
onSelect?.(event, node);
}

function handleFocusEvent(event) {
if (event.type === 'blur') {
const {
Expand All @@ -78,6 +80,7 @@ export default function TreeView({
currentFocusedNode.tabIndex = 0;
}
}

let focusTarget = false;
const nodesWithProps = React.Children.map(children, (node) => {
const sharedNodeProps = {
Expand All @@ -99,17 +102,55 @@ export default function TreeView({

function handleKeyDown(event) {
event.stopPropagation();
if (matches(event, [keys.ArrowUp, keys.ArrowDown])) {
if (
matches(event, [
keys.ArrowUp,
keys.ArrowDown,
keys.Home,
keys.End,
{ code: 'KeyA' },
])
) {
event.preventDefault();
}

treeWalker.current.currentNode = event.target;
let nextFocusNode;

if (match(event, keys.ArrowUp)) {
nextFocusNode = treeWalker.current.previousNode();
}
if (match(event, keys.ArrowDown)) {
nextFocusNode = treeWalker.current.nextNode();
}
if (matches(event, [keys.Home, keys.End, { code: 'KeyA' }])) {
const nodeIds = [];

if (matches(event, [keys.Home, keys.End])) {
if (multiselect && event.shiftKey && event.ctrlKey) {
nodeIds.push(treeWalker.current.currentNode?.id);
}
while (
match(event, keys.Home)
? treeWalker.current.previousNode()
: treeWalker.current.nextNode()
) {
nextFocusNode = treeWalker.current.currentNode;

if (multiselect && event.shiftKey && event.ctrlKey) {
nodeIds.push(nextFocusNode?.id);
}
}
}
if (match(event, { code: 'KeyA' }) && event.ctrlKey) {
treeWalker.current.currentNode = treeWalker.current.root;

while (treeWalker.current.nextNode()) {
nodeIds.push(treeWalker.current.currentNode?.id);
}
}
setSelected(selected.concat(nodeIds));
}
if (nextFocusNode && nextFocusNode !== event.target) {
resetNodeTabIndices();
nextFocusNode.tabIndex = 0;
Expand Down
13 changes: 13 additions & 0 deletions packages/react/src/internal/keyboard/keys.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ export const Tab = {
key: 'Tab',
which: 9,
keyCode: 9,
code: 'Tab',
};

export const Enter = {
key: 'Enter',
which: 13,
keyCode: 13,
code: 'Enter',
};

export const Escape = {
Expand All @@ -25,64 +27,75 @@ export const Escape = {
],
which: 27,
keyCode: 27,
code: 'Esc',
};

export const Space = {
key: ' ',
which: 32,
keyCode: 32,
code: 'Space',
};

export const PageUp = {
key: 'PageUp',
which: 33,
keyCode: 33,
code: 'Numpad9',
};

export const PageDown = {
key: 'PageDown',
which: 34,
keyCode: 34,
code: 'Numpad3',
};

export const End = {
key: 'End',
which: 35,
keyCode: 35,
code: 'Numpad1',
};

export const Home = {
key: 'Home',
which: 36,
keyCode: 36,
code: 'Numpad7',
};

export const ArrowLeft = {
key: 'ArrowLeft',
which: 37,
keyCode: 37,
code: 'ArrowLeft',
};

export const ArrowUp = {
key: 'ArrowUp',
which: 38,
keyCode: 38,
code: 'ArrowUp',
};

export const ArrowRight = {
key: 'ArrowRight',
which: 39,
keyCode: 39,
code: 'ArrowRight',
};

export const ArrowDown = {
key: 'ArrowDown',
which: 40,
keyCode: 40,
code: 'ArrowDown',
};

export const Delete = {
key: 'Delete',
which: 8 || 46,
keyCode: 8 || 46,
code: 'ArrowDecimal',
};
5 changes: 3 additions & 2 deletions packages/react/src/internal/keyboard/match.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export function matches(event, keysToMatch) {
* @param {Key} key
* @returns {boolean}
*/
export function match(eventOrCode, { key, which, keyCode } = {}) {
export function match(eventOrCode, { key, which, keyCode, code } = {}) {
if (typeof eventOrCode === 'string') {
return eventOrCode === key;
}
Expand All @@ -73,7 +73,8 @@ export function match(eventOrCode, { key, which, keyCode } = {}) {
return (
eventOrCode.key === key ||
eventOrCode.which === which ||
eventOrCode.keyCode === keyCode
eventOrCode.keyCode === keyCode ||
eventOrCode.code === code
);
}

Expand Down

0 comments on commit 34f1309

Please sign in to comment.