From 196f03b84e40282e3427401757806f84e19497f9 Mon Sep 17 00:00:00 2001
From: Matiss Janis Aboltins <matiss@mja.lv>
Date: Fri, 7 Jun 2024 19:21:09 +0100
Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20(tooltip)=20refactoring=20?=
 =?UTF-8?q?to=20react-aria=20(vol.8)=20(#2822)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/components/budget/BudgetTable.jsx     |  61 +++++-----
 .../budget/report/BalanceTooltip.tsx          |  48 --------
 .../budget/report/ReportComponents.tsx        | 110 ++++++++++--------
 .../report/budgetsummary/BudgetSummary.tsx    |  81 +++++++------
 .../budget/report/budgetsummary/Saved.tsx     |  72 ++++++------
 .../rollover/budgetsummary/BudgetSummary.tsx  |  89 +++++++-------
 .../rollover/budgetsummary/TotalsList.tsx     |  21 ++--
 .../src/components/tooltips.tsx               |  21 ----
 upcoming-release-notes/2822.md                |   6 +
 9 files changed, 228 insertions(+), 281 deletions(-)
 delete mode 100644 packages/desktop-client/src/components/budget/report/BalanceTooltip.tsx
 create mode 100644 upcoming-release-notes/2822.md

diff --git a/packages/desktop-client/src/components/budget/BudgetTable.jsx b/packages/desktop-client/src/components/budget/BudgetTable.jsx
index c9bd7acec..76ff7a605 100644
--- a/packages/desktop-client/src/components/budget/BudgetTable.jsx
+++ b/packages/desktop-client/src/components/budget/BudgetTable.jsx
@@ -1,10 +1,9 @@
-import React, { useRef, useState } from 'react';
+import React, { useState } from 'react';
 
 import { useCategories } from '../../hooks/useCategories';
 import { useLocalPref } from '../../hooks/useLocalPref';
 import { theme, styles } from '../../style';
 import { View } from '../common/View';
-import { IntersectionBoundary } from '../tooltips';
 
 import { BudgetCategories } from './BudgetCategories';
 import { BudgetSummaries } from './BudgetSummaries';
@@ -30,7 +29,6 @@ export function BudgetTable(props) {
     onBudgetAction,
   } = props;
 
-  const budgetCategoriesRef = useRef();
   const { grouped: categoryGroups } = useCategories();
   const [collapsedGroupIds = [], setCollapsedGroupIdsPref] =
     useLocalPref('budget.collapsed');
@@ -202,41 +200,38 @@ export function BudgetTable(props) {
           expandAllCategories={expandAllCategories}
           collapseAllCategories={collapseAllCategories}
         />
-        <IntersectionBoundary.Provider value={budgetCategoriesRef}>
+        <View
+          style={{
+            overflowY: 'scroll',
+            overflowAnchor: 'none',
+            flex: 1,
+            paddingLeft: 5,
+            paddingRight: 5,
+          }}
+        >
           <View
             style={{
-              overflowY: 'scroll',
-              overflowAnchor: 'none',
-              flex: 1,
-              paddingLeft: 5,
-              paddingRight: 5,
+              flexShrink: 0,
             }}
-            innerRef={budgetCategoriesRef}
+            onKeyDown={onKeyDown}
           >
-            <View
-              style={{
-                flexShrink: 0,
-              }}
-              onKeyDown={onKeyDown}
-            >
-              <BudgetCategories
-                categoryGroups={categoryGroups}
-                editingCell={editing}
-                dataComponents={dataComponents}
-                onEditMonth={onEditMonth}
-                onEditName={onEditName}
-                onSaveCategory={onSaveCategory}
-                onSaveGroup={onSaveGroup}
-                onDeleteCategory={onDeleteCategory}
-                onDeleteGroup={onDeleteGroup}
-                onReorderCategory={_onReorderCategory}
-                onReorderGroup={_onReorderGroup}
-                onBudgetAction={onBudgetAction}
-                onShowActivity={onShowActivity}
-              />
-            </View>
+            <BudgetCategories
+              categoryGroups={categoryGroups}
+              editingCell={editing}
+              dataComponents={dataComponents}
+              onEditMonth={onEditMonth}
+              onEditName={onEditName}
+              onSaveCategory={onSaveCategory}
+              onSaveGroup={onSaveGroup}
+              onDeleteCategory={onDeleteCategory}
+              onDeleteGroup={onDeleteGroup}
+              onReorderCategory={_onReorderCategory}
+              onReorderGroup={_onReorderGroup}
+              onBudgetAction={onBudgetAction}
+              onShowActivity={onShowActivity}
+            />
           </View>
-        </IntersectionBoundary.Provider>
+        </View>
       </MonthsProvider>
     </View>
   );
diff --git a/packages/desktop-client/src/components/budget/report/BalanceTooltip.tsx b/packages/desktop-client/src/components/budget/report/BalanceTooltip.tsx
deleted file mode 100644
index 91aa1ade6..000000000
--- a/packages/desktop-client/src/components/budget/report/BalanceTooltip.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import React from 'react';
-
-import { Tooltip } from '../../tooltips';
-
-import { BalanceMenu } from './BalanceMenu';
-
-type BalanceTooltipProps = {
-  categoryId: string;
-  tooltip: { close: () => void };
-  month: string;
-  onBudgetAction: (month: string, action: string, arg: unknown) => void;
-  onClose?: () => void;
-};
-
-export function BalanceTooltip({
-  categoryId,
-  tooltip,
-  month,
-  onBudgetAction,
-  onClose,
-  ...tooltipProps
-}: BalanceTooltipProps) {
-  const _onClose = () => {
-    tooltip.close();
-    onClose?.();
-  };
-
-  return (
-    <Tooltip
-      position="bottom-right"
-      width={200}
-      style={{ padding: 0 }}
-      onClose={_onClose}
-      {...tooltipProps}
-    >
-      <BalanceMenu
-        categoryId={categoryId}
-        onCarryover={carryover => {
-          onBudgetAction?.(month, 'carryover', {
-            category: categoryId,
-            flag: carryover,
-          });
-          _onClose();
-        }}
-      />
-    </Tooltip>
-  );
-}
diff --git a/packages/desktop-client/src/components/budget/report/ReportComponents.tsx b/packages/desktop-client/src/components/budget/report/ReportComponents.tsx
index 8b05023d2..a9f1d8c6f 100644
--- a/packages/desktop-client/src/components/budget/report/ReportComponents.tsx
+++ b/packages/desktop-client/src/components/budget/report/ReportComponents.tsx
@@ -1,5 +1,5 @@
 // @ts-strict-ignore
-import React, { memo, useState } from 'react';
+import React, { memo, useRef, useState } from 'react';
 
 import { reportBudget } from 'loot-core/src/client/queries';
 import { evalArithmetic } from 'loot-core/src/shared/arithmetic';
@@ -8,16 +8,16 @@ import { integerToCurrency, amountToInteger } from 'loot-core/src/shared/util';
 import { SvgCheveronDown } from '../../../icons/v1';
 import { styles, theme, type CSSProperties } from '../../../style';
 import { Button } from '../../common/Button';
+import { Popover } from '../../common/Popover';
 import { Text } from '../../common/Text';
 import { View } from '../../common/View';
 import { CellValue } from '../../spreadsheet/CellValue';
 import { useFormat } from '../../spreadsheet/useFormat';
 import { Field, SheetCell } from '../../table';
-import { Tooltip, useTooltip } from '../../tooltips';
 import { BalanceWithCarryover } from '../BalanceWithCarryover';
 import { makeAmountGrey } from '../util';
 
-import { BalanceTooltip } from './BalanceTooltip';
+import { BalanceMenu } from './BalanceMenu';
 import { BudgetMenu } from './BudgetMenu';
 
 const headerLabelStyle: CSSProperties = {
@@ -156,9 +156,12 @@ export const CategoryMonth = memo(function CategoryMonth({
   onBudgetAction,
   onShowActivity,
 }: CategoryMonthProps) {
-  const balanceTooltip = useTooltip();
   const [menuOpen, setMenuOpen] = useState(false);
   const [hover, setHover] = useState(false);
+  const triggerRef = useRef(null);
+
+  const [balanceMenuOpen, setBalanceMenuOpen] = useState(false);
+  const triggerBalanceMenuRef = useRef(null);
 
   return (
     <View
@@ -196,6 +199,7 @@ export const CategoryMonth = memo(function CategoryMonth({
             }}
           >
             <Button
+              ref={triggerRef}
               type="bare"
               onClick={e => {
                 e.stopPropagation();
@@ -212,44 +216,39 @@ export const CategoryMonth = memo(function CategoryMonth({
                 style={menuOpen && { opacity: 1 }}
               />
             </Button>
-            {menuOpen && (
-              <Tooltip
-                position="bottom-left"
-                width={200}
-                style={{ padding: 0 }}
-                onClose={() => setMenuOpen(false)}
-              >
-                <BudgetMenu
-                  onCopyLastMonthAverage={() => {
-                    onBudgetAction?.(month, 'copy-single-last', {
-                      category: category.id,
-                    });
-                  }}
-                  onSetMonthsAverage={numberOfMonths => {
-                    if (
-                      numberOfMonths !== 3 &&
-                      numberOfMonths !== 6 &&
-                      numberOfMonths !== 12
-                    ) {
-                      return;
-                    }
 
-                    onBudgetAction?.(
-                      month,
-                      `set-single-${numberOfMonths}-avg`,
-                      {
-                        category: category.id,
-                      },
-                    );
-                  }}
-                  onApplyBudgetTemplate={() => {
-                    onBudgetAction?.(month, 'apply-single-category-template', {
-                      category: category.id,
-                    });
-                  }}
-                />
-              </Tooltip>
-            )}
+            <Popover
+              triggerRef={triggerRef}
+              isOpen={menuOpen}
+              onOpenChange={() => setMenuOpen(false)}
+              placement="bottom start"
+            >
+              <BudgetMenu
+                onCopyLastMonthAverage={() => {
+                  onBudgetAction?.(month, 'copy-single-last', {
+                    category: category.id,
+                  });
+                }}
+                onSetMonthsAverage={numberOfMonths => {
+                  if (
+                    numberOfMonths !== 3 &&
+                    numberOfMonths !== 6 &&
+                    numberOfMonths !== 12
+                  ) {
+                    return;
+                  }
+
+                  onBudgetAction?.(month, `set-single-${numberOfMonths}-avg`, {
+                    category: category.id,
+                  });
+                }}
+                onApplyBudgetTemplate={() => {
+                  onBudgetAction?.(month, 'apply-single-category-template', {
+                    category: category.id,
+                  });
+                }}
+              />
+            </Popover>
           </View>
         )}
         <SheetCell
@@ -323,7 +322,12 @@ export const CategoryMonth = memo(function CategoryMonth({
           width="flex"
           style={{ paddingRight: styles.monthRightPadding, textAlign: 'right' }}
         >
-          <span {...(category.is_income ? {} : balanceTooltip.getOpenEvents())}>
+          <span
+            ref={triggerBalanceMenuRef}
+            {...(category.is_income
+              ? {}
+              : { onClick: () => setBalanceMenuOpen(true) })}
+          >
             <BalanceWithCarryover
               disabled={category.is_income}
               carryover={reportBudget.catCarryover(category.id)}
@@ -335,14 +339,24 @@ export const CategoryMonth = memo(function CategoryMonth({
               }}
             />
           </span>
-          {balanceTooltip.isOpen && (
-            <BalanceTooltip
+
+          <Popover
+            triggerRef={triggerBalanceMenuRef}
+            isOpen={balanceMenuOpen}
+            onOpenChange={() => setBalanceMenuOpen(false)}
+            placement="bottom end"
+          >
+            <BalanceMenu
               categoryId={category.id}
-              tooltip={balanceTooltip}
-              month={month}
-              onBudgetAction={onBudgetAction}
+              onCarryover={carryover => {
+                onBudgetAction?.(month, 'carryover', {
+                  category: category.id,
+                  flag: carryover,
+                });
+                setBalanceMenuOpen(false);
+              }}
             />
-          )}
+          </Popover>
         </Field>
       )}
     </View>
diff --git a/packages/desktop-client/src/components/budget/report/budgetsummary/BudgetSummary.tsx b/packages/desktop-client/src/components/budget/report/budgetsummary/BudgetSummary.tsx
index a2202bad3..990121924 100644
--- a/packages/desktop-client/src/components/budget/report/budgetsummary/BudgetSummary.tsx
+++ b/packages/desktop-client/src/components/budget/report/budgetsummary/BudgetSummary.tsx
@@ -1,5 +1,5 @@
 // @ts-strict-ignore
-import React, { useState } from 'react';
+import React, { useRef, useState } from 'react';
 
 import { css } from 'glamor';
 
@@ -9,11 +9,11 @@ import { SvgDotsHorizontalTriple } from '../../../../icons/v1';
 import { SvgArrowButtonDown1, SvgArrowButtonUp1 } from '../../../../icons/v2';
 import { theme, styles } from '../../../../style';
 import { Button } from '../../../common/Button';
+import { Popover } from '../../../common/Popover';
 import { Stack } from '../../../common/Stack';
 import { View } from '../../../common/View';
 import { NotesButton } from '../../../NotesButton';
 import { NamespaceContext } from '../../../spreadsheet/NamespaceContext';
-import { Tooltip } from '../../../tooltips';
 import { useReport } from '../ReportContext';
 
 import { BudgetMonthMenu } from './BudgetMonthMenu';
@@ -33,6 +33,8 @@ export function BudgetSummary({ month }: BudgetSummaryProps) {
   } = useReport();
 
   const [menuOpen, setMenuOpen] = useState(false);
+  const triggerRef = useRef(null);
+
   function onMenuOpen() {
     setMenuOpen(true);
   }
@@ -129,48 +131,51 @@ export function BudgetSummary({ month }: BudgetSummaryProps) {
               />
             </View>
             <View style={{ userSelect: 'none' }}>
-              <Button type="bare" aria-label="Menu" onClick={onMenuOpen}>
+              <Button
+                ref={triggerRef}
+                type="bare"
+                aria-label="Menu"
+                onClick={onMenuOpen}
+              >
                 <SvgDotsHorizontalTriple
                   width={15}
                   height={15}
                   style={{ color: theme.pageTextLight }}
                 />
               </Button>
-              {menuOpen && (
-                <Tooltip
-                  position="bottom-right"
-                  width={200}
-                  style={{ padding: 0 }}
-                  onClose={onMenuClose}
-                >
-                  <BudgetMonthMenu
-                    onCopyLastMonthBudget={() => {
-                      onBudgetAction(month, 'copy-last');
-                      onMenuClose();
-                    }}
-                    onSetBudgetsToZero={() => {
-                      onBudgetAction(month, 'set-zero');
-                      onMenuClose();
-                    }}
-                    onSetMonthsAverage={numberOfMonths => {
-                      onBudgetAction(month, `set-${numberOfMonths}-avg`);
-                      onMenuClose();
-                    }}
-                    onCheckTemplates={() => {
-                      onBudgetAction(month, 'check-templates');
-                      onMenuClose();
-                    }}
-                    onApplyBudgetTemplates={() => {
-                      onBudgetAction(month, 'apply-goal-template');
-                      onMenuClose();
-                    }}
-                    onOverwriteWithBudgetTemplates={() => {
-                      onBudgetAction(month, 'overwrite-goal-template');
-                      onMenuClose();
-                    }}
-                  />
-                </Tooltip>
-              )}
+
+              <Popover
+                triggerRef={triggerRef}
+                isOpen={menuOpen}
+                onOpenChange={onMenuClose}
+              >
+                <BudgetMonthMenu
+                  onCopyLastMonthBudget={() => {
+                    onBudgetAction(month, 'copy-last');
+                    onMenuClose();
+                  }}
+                  onSetBudgetsToZero={() => {
+                    onBudgetAction(month, 'set-zero');
+                    onMenuClose();
+                  }}
+                  onSetMonthsAverage={numberOfMonths => {
+                    onBudgetAction(month, `set-${numberOfMonths}-avg`);
+                    onMenuClose();
+                  }}
+                  onCheckTemplates={() => {
+                    onBudgetAction(month, 'check-templates');
+                    onMenuClose();
+                  }}
+                  onApplyBudgetTemplates={() => {
+                    onBudgetAction(month, 'apply-goal-template');
+                    onMenuClose();
+                  }}
+                  onOverwriteWithBudgetTemplates={() => {
+                    onBudgetAction(month, 'overwrite-goal-template');
+                    onMenuClose();
+                  }}
+                />
+              </Popover>
             </View>
           </View>
         </View>
diff --git a/packages/desktop-client/src/components/budget/report/budgetsummary/Saved.tsx b/packages/desktop-client/src/components/budget/report/budgetsummary/Saved.tsx
index b17906ec4..883021b5e 100644
--- a/packages/desktop-client/src/components/budget/report/budgetsummary/Saved.tsx
+++ b/packages/desktop-client/src/components/budget/report/budgetsummary/Saved.tsx
@@ -6,13 +6,12 @@ import { reportBudget } from 'loot-core/src/client/queries';
 
 import { theme, type CSSProperties, styles } from '../../../../style';
 import { AlignedText } from '../../../common/AlignedText';
-import { HoverTarget } from '../../../common/HoverTarget';
 import { Text } from '../../../common/Text';
+import { Tooltip } from '../../../common/Tooltip';
 import { View } from '../../../common/View';
 import { PrivacyFilter } from '../../../PrivacyFilter';
 import { useFormat } from '../../../spreadsheet/useFormat';
 import { useSheetValue } from '../../../spreadsheet/useSheetValue';
-import { Tooltip } from '../../../tooltips';
 import { makeAmountFullStyle } from '../../util';
 
 type SavedProps = {
@@ -25,6 +24,7 @@ export function Saved({ projected, style }: SavedProps) {
   const format = useFormat();
   const saved = projected ? budgetedSaved : totalSaved;
   const isNegative = saved < 0;
+  const diff = totalSaved - budgetedSaved;
 
   return (
     <View style={{ alignItems: 'center', fontSize: 14, ...style }}>
@@ -36,42 +36,36 @@ export function Saved({ projected, style }: SavedProps) {
         </View>
       )}
 
-      <HoverTarget
-        renderContent={() => {
-          if (!projected) {
-            const diff = totalSaved - budgetedSaved;
-            return (
-              <Tooltip
-                position="bottom-center"
-                style={{ padding: 10, fontSize: 14 }}
-              >
-                <AlignedText
-                  left="Projected Savings:"
-                  right={
-                    <Text
-                      style={{
-                        ...makeAmountFullStyle(budgetedSaved),
-                        ...styles.tnum,
-                      }}
-                    >
-                      {format(budgetedSaved, 'financial-with-sign')}
-                    </Text>
-                  }
-                />
-                <AlignedText
-                  left="Difference:"
-                  right={
-                    <Text
-                      style={{ ...makeAmountFullStyle(diff), ...styles.tnum }}
-                    >
-                      {format(diff, 'financial-with-sign')}
-                    </Text>
-                  }
-                />
-              </Tooltip>
-            );
-          }
-          return null;
+      <Tooltip
+        style={{ ...styles.tooltip, fontSize: 14, padding: 10 }}
+        content={
+          <>
+            <AlignedText
+              left="Projected Savings:"
+              right={
+                <Text
+                  style={{
+                    ...makeAmountFullStyle(budgetedSaved),
+                    ...styles.tnum,
+                  }}
+                >
+                  {format(budgetedSaved, 'financial-with-sign')}
+                </Text>
+              }
+            />
+            <AlignedText
+              left="Difference:"
+              right={
+                <Text style={{ ...makeAmountFullStyle(diff), ...styles.tnum }}>
+                  {format(diff, 'financial-with-sign')}
+                </Text>
+              }
+            />
+          </>
+        }
+        placement="bottom"
+        triggerProps={{
+          isDisabled: Boolean(projected),
         }}
       >
         <View
@@ -90,7 +84,7 @@ export function Saved({ projected, style }: SavedProps) {
             {format(saved, 'financial')}
           </PrivacyFilter>
         </View>
-      </HoverTarget>
+      </Tooltip>
     </View>
   );
 }
diff --git a/packages/desktop-client/src/components/budget/rollover/budgetsummary/BudgetSummary.tsx b/packages/desktop-client/src/components/budget/rollover/budgetsummary/BudgetSummary.tsx
index b1f65c7f9..d74c0d999 100644
--- a/packages/desktop-client/src/components/budget/rollover/budgetsummary/BudgetSummary.tsx
+++ b/packages/desktop-client/src/components/budget/rollover/budgetsummary/BudgetSummary.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import React, { useRef, useState } from 'react';
 
 import { css } from 'glamor';
 
@@ -8,10 +8,10 @@ import { SvgDotsHorizontalTriple } from '../../../../icons/v1';
 import { SvgArrowButtonDown1, SvgArrowButtonUp1 } from '../../../../icons/v2';
 import { theme, styles } from '../../../../style';
 import { Button } from '../../../common/Button';
+import { Popover } from '../../../common/Popover';
 import { View } from '../../../common/View';
 import { NotesButton } from '../../../NotesButton';
 import { NamespaceContext } from '../../../spreadsheet/NamespaceContext';
-import { Tooltip } from '../../../tooltips';
 import { useRollover } from '../RolloverContext';
 
 import { BudgetMonthMenu } from './BudgetMonthMenu';
@@ -31,6 +31,8 @@ export function BudgetSummary({ month }: BudgetSummaryProps) {
   } = useRollover();
 
   const [menuOpen, setMenuOpen] = useState(false);
+  const triggerRef = useRef(null);
+
   function onMenuOpen() {
     setMenuOpen(true);
   }
@@ -131,52 +133,55 @@ export function BudgetSummary({ month }: BudgetSummaryProps) {
               />
             </View>
             <View style={{ userSelect: 'none', marginLeft: 2 }}>
-              <Button type="bare" aria-label="Menu" onClick={onMenuOpen}>
+              <Button
+                ref={triggerRef}
+                type="bare"
+                aria-label="Menu"
+                onClick={onMenuOpen}
+              >
                 <SvgDotsHorizontalTriple
                   width={15}
                   height={15}
                   style={{ color: theme.pageTextLight }}
                 />
               </Button>
-              {menuOpen && (
-                <Tooltip
-                  position="bottom-right"
-                  width={200}
-                  style={{ padding: 0 }}
-                  onClose={onMenuClose}
-                >
-                  <BudgetMonthMenu
-                    onCopyLastMonthBudget={() => {
-                      onBudgetAction(month, 'copy-last');
-                      onMenuClose();
-                    }}
-                    onSetBudgetsToZero={() => {
-                      onBudgetAction(month, 'set-zero');
-                      onMenuClose();
-                    }}
-                    onSetMonthsAverage={numberOfMonths => {
-                      onBudgetAction(month, `set-${numberOfMonths}-avg`);
-                      onMenuClose();
-                    }}
-                    onCheckTemplates={() => {
-                      onBudgetAction(month, 'check-templates');
-                      onMenuClose();
-                    }}
-                    onApplyBudgetTemplates={() => {
-                      onBudgetAction(month, 'apply-goal-template');
-                      onMenuClose();
-                    }}
-                    onOverwriteWithBudgetTemplates={() => {
-                      onBudgetAction(month, 'overwrite-goal-template');
-                      onMenuClose();
-                    }}
-                    onEndOfMonthCleanup={() => {
-                      onBudgetAction(month, 'cleanup-goal-template');
-                      onMenuClose();
-                    }}
-                  />
-                </Tooltip>
-              )}
+
+              <Popover
+                triggerRef={triggerRef}
+                isOpen={menuOpen}
+                onOpenChange={onMenuClose}
+              >
+                <BudgetMonthMenu
+                  onCopyLastMonthBudget={() => {
+                    onBudgetAction(month, 'copy-last');
+                    onMenuClose();
+                  }}
+                  onSetBudgetsToZero={() => {
+                    onBudgetAction(month, 'set-zero');
+                    onMenuClose();
+                  }}
+                  onSetMonthsAverage={numberOfMonths => {
+                    onBudgetAction(month, `set-${numberOfMonths}-avg`);
+                    onMenuClose();
+                  }}
+                  onCheckTemplates={() => {
+                    onBudgetAction(month, 'check-templates');
+                    onMenuClose();
+                  }}
+                  onApplyBudgetTemplates={() => {
+                    onBudgetAction(month, 'apply-goal-template');
+                    onMenuClose();
+                  }}
+                  onOverwriteWithBudgetTemplates={() => {
+                    onBudgetAction(month, 'overwrite-goal-template');
+                    onMenuClose();
+                  }}
+                  onEndOfMonthCleanup={() => {
+                    onBudgetAction(month, 'cleanup-goal-template');
+                    onMenuClose();
+                  }}
+                />
+              </Popover>
             </View>
           </View>
         </View>
diff --git a/packages/desktop-client/src/components/budget/rollover/budgetsummary/TotalsList.tsx b/packages/desktop-client/src/components/budget/rollover/budgetsummary/TotalsList.tsx
index 3c906d580..fe3fb0b81 100644
--- a/packages/desktop-client/src/components/budget/rollover/budgetsummary/TotalsList.tsx
+++ b/packages/desktop-client/src/components/budget/rollover/budgetsummary/TotalsList.tsx
@@ -5,11 +5,10 @@ import { rolloverBudget } from 'loot-core/src/client/queries';
 import { styles, type CSSProperties } from '../../../../style';
 import { AlignedText } from '../../../common/AlignedText';
 import { Block } from '../../../common/Block';
-import { HoverTarget } from '../../../common/HoverTarget';
+import { Tooltip } from '../../../common/Tooltip';
 import { View } from '../../../common/View';
 import { CellValue } from '../../../spreadsheet/CellValue';
 import { useFormat } from '../../../spreadsheet/useFormat';
-import { Tooltip } from '../../../tooltips';
 
 type TotalsListProps = {
   prevMonthName: string;
@@ -34,13 +33,10 @@ export function TotalsList({ prevMonthName, style }: TotalsListProps) {
           minWidth: 50,
         }}
       >
-        <HoverTarget
-          style={{ flexShrink: 0 }}
-          renderContent={() => (
-            <Tooltip
-              width={200}
-              style={{ lineHeight: 1.5, padding: '6px 10px' }}
-            >
+        <Tooltip
+          style={{ ...styles.tooltip, lineHeight: 1.5, padding: '6px 10px' }}
+          content={
+            <>
               <AlignedText
                 left="Income:"
                 right={
@@ -61,15 +57,16 @@ export function TotalsList({ prevMonthName, style }: TotalsListProps) {
                   />
                 }
               />
-            </Tooltip>
-          )}
+            </>
+          }
+          placement="bottom end"
         >
           <CellValue
             binding={rolloverBudget.incomeAvailable}
             type="financial"
             style={{ fontWeight: 600 }}
           />
-        </HoverTarget>
+        </Tooltip>
 
         <CellValue
           binding={rolloverBudget.lastMonthOverspent}
diff --git a/packages/desktop-client/src/components/tooltips.tsx b/packages/desktop-client/src/components/tooltips.tsx
index e17a6dba0..b6182a5d0 100644
--- a/packages/desktop-client/src/components/tooltips.tsx
+++ b/packages/desktop-client/src/components/tooltips.tsx
@@ -3,11 +3,8 @@ import {
   Component,
   createContext,
   createRef,
-  useState,
   type RefObject,
   type ReactNode,
-  type MouseEventHandler,
-  type MouseEvent,
   type ContextType,
 } from 'react';
 import ReactDOM from 'react-dom';
@@ -18,24 +15,6 @@ import { type CSSProperties, styles, theme } from '../style';
 
 export const IntersectionBoundary = createContext<RefObject<HTMLElement>>(null);
 
-// @deprecated: please use `Tooltip` component in `common` folder
-export function useTooltip() {
-  const [isOpen, setIsOpen] = useState<boolean>(false);
-
-  return {
-    getOpenEvents: (events: { onClick?: MouseEventHandler } = {}) => ({
-      onClick: (e: MouseEvent) => {
-        e.stopPropagation();
-        events.onClick?.(e);
-        setIsOpen(true);
-      },
-    }),
-    isOpen,
-    open: () => setIsOpen(true),
-    close: () => setIsOpen(false),
-  };
-}
-
 type TooltipPosition =
   | 'top'
   | 'top-left'
diff --git a/upcoming-release-notes/2822.md b/upcoming-release-notes/2822.md
new file mode 100644
index 000000000..e49a69b05
--- /dev/null
+++ b/upcoming-release-notes/2822.md
@@ -0,0 +1,6 @@
+---
+category: Maintenance
+authors: [MatissJanis]
+---
+
+Migrating native `Tooltip` component to react-aria Tooltip/Popover (vol.8)
-- 
GitLab