anchor.diff:  
       if (isBelowViewport) {
         // Scroll so selected row is the last full item displayed in the viewport.
  -      // To do this we need to be showing the (minCompleteItemsInView - 1)
  +      // To do this we need to be showing the (minCompleteItemsInView + 1)
         // previous item  at the top.
         scrollController.animateTo(
  -        (newSelectedNodeIndex - minCompleteItemsInView - 1) *
  +        (newSelectedNodeIndex - minCompleteItemsInView + 1) *
               _Table.defaultRowHeight,
           duration: defaultDuration,
           curve: defaultCurve,
  
positive.code:     }
      assert(selectedNode == items[selectedNodeIndex]);
  
      if (event.logicalKey == LogicalKeyboardKey.arrowDown ||
          event.logicalKey == LogicalKeyboardKey.arrowUp) {
        _moveSelection(event.logicalKey, scrollController, constraints.maxHeight);
      }
      // TODO(gmoothart): Add expand/collapse with left/right keys
    }
  
    void _moveSelection(
      LogicalKeyboardKey key,
      ScrollController scrollController,
      double viewportHeight,
    ) {
  
negative.code:     final firstItemIndex =
          (scrollController.offset / _Table.defaultRowHeight).ceil();
  
      // '-1' in the following calculations is needed because the header row
      // occupies space in the viewport so we must subtract it out.
      final minCompleteItemsInView =
          (viewportHeight / _Table.defaultRowHeight).floor() - 1;
      final lastItemIndex = firstItemIndex + minCompleteItemsInView - 1;
      int newSelectedNodeIndex;
  
      switch (scrollKind) {
        case ScrollKind.down:
          newSelectedNodeIndex = min(selectedNodeIndex + 1, items.length - 1);
          break;
        case ScrollKind.up:
          newSelectedNodeIndex = max(selectedNodeIndex - 1, 0);
          break;
        case ScrollKind.parent:
          newSelectedNodeIndex = items.indexOf(selectedNode.parent);
          break;
      }
  
      final newSelectedNode = items[newSelectedNodeIndex];
  