From a7964cda7708d829e96dbe5947f3ac055ed848c2 Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 2 Jun 2022 11:03:50 -0500 Subject: [PATCH] fix(TreeView): prevent disabled node selection and expansion (#11520) * refactor(treeview): unnest styles * fix(TreeView): prevent disabled node selection on ctrl+a * fix(TreeView): prevent disabled node selection on ctrl+shift+home/end * fix(TreeNode): prevent disabled node expansion Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../react/src/components/TreeView/TreeNode.js | 6 + .../react/src/components/TreeView/TreeView.js | 18 +- .../scss/components/treeview/_treeview.scss | 234 +++++++++--------- 3 files changed, 138 insertions(+), 120 deletions(-) diff --git a/packages/react/src/components/TreeView/TreeNode.js b/packages/react/src/components/TreeView/TreeNode.js index 18a0ea02e0f0..a6beea2cf447 100644 --- a/packages/react/src/components/TreeView/TreeNode.js +++ b/packages/react/src/components/TreeView/TreeNode.js @@ -61,6 +61,9 @@ export default function TreeNode({ [`${prefix}--tree-parent-node__toggle-icon--expanded`]: expanded, }); function handleToggleClick(event) { + if (disabled) { + return; + } onToggle?.(event, { id, isExpanded: !expanded, label, value }); setExpanded(!expanded); } @@ -73,6 +76,9 @@ export default function TreeNode({ } } function handleKeyDown(event) { + if (disabled) { + return; + } if (matches(event, [keys.ArrowLeft, keys.ArrowRight, keys.Enter])) { event.stopPropagation(); } diff --git a/packages/react/src/components/TreeView/TreeView.js b/packages/react/src/components/TreeView/TreeView.js index 86c7752393ea..c10646b2806c 100644 --- a/packages/react/src/components/TreeView/TreeView.js +++ b/packages/react/src/components/TreeView/TreeView.js @@ -127,7 +127,12 @@ export default function TreeView({ const nodeIds = []; if (matches(event, [keys.Home, keys.End])) { - if (multiselect && event.shiftKey && event.ctrlKey) { + if ( + multiselect && + event.shiftKey && + event.ctrlKey && + !treeWalker.current.currentNode.getAttribute('aria-disabled') + ) { nodeIds.push(treeWalker.current.currentNode?.id); } while ( @@ -137,7 +142,12 @@ export default function TreeView({ ) { nextFocusNode = treeWalker.current.currentNode; - if (multiselect && event.shiftKey && event.ctrlKey) { + if ( + multiselect && + event.shiftKey && + event.ctrlKey && + !nextFocusNode.getAttribute('aria-disabled') + ) { nodeIds.push(nextFocusNode?.id); } } @@ -146,7 +156,9 @@ export default function TreeView({ treeWalker.current.currentNode = treeWalker.current.root; while (treeWalker.current.nextNode()) { - nodeIds.push(treeWalker.current.currentNode?.id); + if (!treeWalker.current.currentNode.getAttribute('aria-disabled')) { + nodeIds.push(treeWalker.current.currentNode?.id); + } } } setSelected(selected.concat(nodeIds)); diff --git a/packages/styles/scss/components/treeview/_treeview.scss b/packages/styles/scss/components/treeview/_treeview.scss index cc11aeef20f8..d539777b6cd5 100644 --- a/packages/styles/scss/components/treeview/_treeview.scss +++ b/packages/styles/scss/components/treeview/_treeview.scss @@ -20,154 +20,154 @@ @mixin treeview { .#{$prefix}--tree { overflow: hidden; + } - .#{$prefix}--tree-node { - padding-left: $spacing-05; - background-color: $layer-01; - color: $text-secondary; - - &:focus { - outline: none; - } - } + .#{$prefix}--tree-node { + padding-left: $spacing-05; + background-color: $layer-01; + color: $text-secondary; - .#{$prefix}--tree-node:focus > .#{$prefix}--tree-node__label { - @include focus-outline('outline'); - } - - .#{$prefix}--tree-node--disabled:focus > .#{$prefix}--tree-node__label { + &:focus { outline: none; } + } - .#{$prefix}--tree-node--disabled, - .#{$prefix}--tree-node--disabled .#{$prefix}--tree-node__label:hover, - .#{$prefix}--tree-node--disabled - .#{$prefix}--tree-node__label:hover - .#{$prefix}--tree-node__label__details { - background-color: $field-01; - color: $text-disabled; - } + .#{$prefix}--tree-node:focus > .#{$prefix}--tree-node__label { + @include focus-outline('outline'); + } - .#{$prefix}--tree-node--disabled .#{$prefix}--tree-parent-node__toggle-icon, - .#{$prefix}--tree-node--disabled .#{$prefix}--tree-node__icon, - .#{$prefix}--tree-node--disabled - .#{$prefix}--tree-node__label:hover - .#{$prefix}--tree-parent-node__toggle-icon, - .#{$prefix}--tree-node--disabled - .#{$prefix}--tree-node__label:hover - .#{$prefix}--tree-node__icon { - fill: $icon-disabled; - } + .#{$prefix}--tree-node--disabled:focus > .#{$prefix}--tree-node__label { + outline: none; + } - .#{$prefix}--tree-node--disabled, - .#{$prefix}--tree-node--disabled - .#{$prefix}--tree-parent-node__toggle-icon:hover { - cursor: not-allowed; - } + .#{$prefix}--tree-node--disabled, + .#{$prefix}--tree-node--disabled .#{$prefix}--tree-node__label:hover, + .#{$prefix}--tree-node--disabled + .#{$prefix}--tree-node__label:hover + .#{$prefix}--tree-node__label__details { + background-color: $field-01; + color: $text-disabled; + } + + .#{$prefix}--tree-node--disabled .#{$prefix}--tree-parent-node__toggle-icon, + .#{$prefix}--tree-node--disabled .#{$prefix}--tree-node__icon, + .#{$prefix}--tree-node--disabled + .#{$prefix}--tree-node__label:hover + .#{$prefix}--tree-parent-node__toggle-icon, + .#{$prefix}--tree-node--disabled + .#{$prefix}--tree-node__label:hover + .#{$prefix}--tree-node__icon { + fill: $icon-disabled; + } - .#{$prefix}--tree-node__label { - @include type-style('body-compact-01'); + .#{$prefix}--tree-node--disabled, + .#{$prefix}--tree-node--disabled + .#{$prefix}--tree-parent-node__toggle-icon:hover { + cursor: not-allowed; + } - display: flex; - min-height: rem(32px); - flex: 1; - align-items: center; + .#{$prefix}--tree-node__label { + @include type-style('body-compact-01'); - &:hover { - background-color: $layer-hover-01; - color: $text-primary; - } - } + display: flex; + min-height: rem(32px); + flex: 1; + align-items: center; - .#{$prefix}--tree-node__label:hover .#{$prefix}--tree-node__label__details { + &:hover { + background-color: $layer-hover-01; color: $text-primary; } + } - .#{$prefix}--tree-node__label:hover - .#{$prefix}--tree-parent-node__toggle-icon, - .#{$prefix}--tree-node__label:hover .#{$prefix}--tree-node__icon { - fill: $icon-primary; - } + .#{$prefix}--tree-node__label:hover .#{$prefix}--tree-node__label__details { + color: $text-primary; + } - .#{$prefix}--tree-leaf-node { - display: flex; - padding-left: $spacing-08; - } + .#{$prefix}--tree-node__label:hover + .#{$prefix}--tree-parent-node__toggle-icon, + .#{$prefix}--tree-node__label:hover .#{$prefix}--tree-node__icon { + fill: $icon-primary; + } - .#{$prefix}--tree-leaf-node.#{$prefix}--tree-node--with-icon { - padding-left: $spacing-07; - } + .#{$prefix}--tree-leaf-node { + display: flex; + padding-left: $spacing-08; + } - .#{$prefix}--tree-node__label__details { - display: flex; - align-items: center; - } + .#{$prefix}--tree-leaf-node.#{$prefix}--tree-node--with-icon { + padding-left: $spacing-07; + } - .#{$prefix}--tree-node--with-icon .#{$prefix}--tree-parent-node__toggle { - margin-right: 0; - } + .#{$prefix}--tree-node__label__details { + display: flex; + align-items: center; + } - .#{$prefix}--tree-parent-node__toggle { - padding: 0; - border: 0; - margin-right: $spacing-03; + .#{$prefix}--tree-node--with-icon .#{$prefix}--tree-parent-node__toggle { + margin-right: 0; + } - &:hover { - cursor: pointer; - } + .#{$prefix}--tree-parent-node__toggle { + padding: 0; + border: 0; + margin-right: $spacing-03; - &:focus { - outline: none; - } + &:hover { + cursor: pointer; } - .#{$prefix}--tree-parent-node__toggle-icon { - fill: $icon-secondary; - transform: rotate(-90deg); - transition: all $duration-fast-02 motion(standard, productive); + &:focus { + outline: none; } + } - .#{$prefix}--tree-parent-node__toggle-icon--expanded { - transform: rotate(0); - } + .#{$prefix}--tree-parent-node__toggle-icon { + fill: $icon-secondary; + transform: rotate(-90deg); + transition: all $duration-fast-02 motion(standard, productive); + } - .#{$prefix}--tree-node__icon { - min-width: 1rem; - min-height: 1rem; - margin-right: $spacing-03; - fill: $icon-secondary; - } + .#{$prefix}--tree-parent-node__toggle-icon--expanded { + transform: rotate(0); + } - .#{$prefix}--tree-node--selected > .#{$prefix}--tree-node__label { - background-color: $layer-selected-01; - color: $text-primary; + .#{$prefix}--tree-node__icon { + min-width: 1rem; + min-height: 1rem; + margin-right: $spacing-03; + fill: $icon-secondary; + } - &:hover { - background-color: $layer-selected-hover-01; - } - } + .#{$prefix}--tree-node--selected > .#{$prefix}--tree-node__label { + background-color: $layer-selected-01; + color: $text-primary; - .#{$prefix}--tree-node--selected - > .#{$prefix}--tree-node__label - .#{$prefix}--tree-parent-node__toggle-icon, - .#{$prefix}--tree-node--selected - > .#{$prefix}--tree-node__label - .#{$prefix}--tree-node__icon { - fill: $icon-primary; + &:hover { + background-color: $layer-selected-hover-01; } + } + + .#{$prefix}--tree-node--selected + > .#{$prefix}--tree-node__label + .#{$prefix}--tree-parent-node__toggle-icon, + .#{$prefix}--tree-node--selected + > .#{$prefix}--tree-node__label + .#{$prefix}--tree-node__icon { + fill: $icon-primary; + } - .#{$prefix}--tree-node--active > .#{$prefix}--tree-node__label { - position: relative; - - &::before { - position: absolute; - top: 0; - left: 0; - width: rem(4px); - height: 100%; - background-color: $interactive; - content: ''; - } + .#{$prefix}--tree-node--active > .#{$prefix}--tree-node__label { + position: relative; + + &::before { + position: absolute; + top: 0; + left: 0; + width: rem(4px); + height: 100%; + background-color: $interactive; + content: ''; } }