Skip to content
Snippets Groups Projects
Unverified Commit 64cd6ee3 authored by Matiss Janis Aboltins's avatar Matiss Janis Aboltins Committed by GitHub
Browse files

:recycle: (tooltip) refactoring to react-aria (vol.9) (#2826)

parent abc46366
No related branches found
No related tags found
No related merge requests found
......@@ -19,7 +19,7 @@ import { InitialFocus } from '../common/InitialFocus';
import { Input } from '../common/Input';
import { Menu } from '../common/Menu';
import { MenuButton } from '../common/MenuButton';
import { MenuTooltip } from '../common/MenuTooltip';
import { Popover } from '../common/Popover';
import { Search } from '../common/Search';
import { Stack } from '../common/Stack';
import { View } from '../common/View';
......@@ -29,7 +29,7 @@ import { NotesButton } from '../NotesButton';
import { SelectedTransactionsButton } from '../transactions/SelectedTransactions';
import { Balances } from './Balance';
import { ReconcilingMessage, ReconcileTooltip } from './Reconcile';
import { ReconcilingMessage, ReconcileMenu } from './Reconcile';
export function AccountHeader({
filteredAmount,
......@@ -86,6 +86,7 @@ export function AccountHeader({
}) {
const [menuOpen, setMenuOpen] = useState(false);
const searchInput = useRef(null);
const triggerRef = useRef(null);
const splitsExpanded = useSplitsExpanded();
const syncServerStatus = useSyncServerStatus();
const isUsingServer = syncServerStatus !== 'no-server';
......@@ -338,9 +339,14 @@ export function AccountHeader({
</Button>
{account ? (
<View>
<MenuButton onClick={() => setMenuOpen(true)} />
<MenuButton ref={triggerRef} onClick={() => setMenuOpen(true)} />
{menuOpen && (
<Popover
triggerRef={triggerRef}
style={{ width: 275 }}
isOpen={menuOpen}
onOpenChange={() => setMenuOpen(false)}
>
<AccountMenu
account={account}
canSync={canSync}
......@@ -356,22 +362,31 @@ export function AccountHeader({
onReconcile={onReconcile}
onClose={() => setMenuOpen(false)}
/>
)}
</Popover>
</View>
) : (
<View>
<MenuButton onClick={() => setMenuOpen(true)} />
<MenuButton ref={triggerRef} onClick={() => setMenuOpen(true)} />
{menuOpen && (
<CategoryMenu
<Popover
triggerRef={triggerRef}
isOpen={menuOpen}
onOpenChange={() => setMenuOpen(false)}
>
<Menu
onMenuSelect={item => {
setMenuOpen(false);
onMenuSelect(item);
}}
onClose={() => setMenuOpen(false)}
isSorted={isSorted}
items={[
isSorted && {
name: 'remove-sorting',
text: 'Remove all sorting',
},
{ name: 'export', text: 'Export' },
]}
/>
)}
</Popover>
</View>
)}
</Stack>
......@@ -418,76 +433,54 @@ function AccountMenu({
const syncServerStatus = useSyncServerStatus();
return tooltip === 'reconcile' ? (
<ReconcileTooltip
<ReconcileMenu
account={account}
onClose={onClose}
onReconcile={onReconcile}
/>
) : (
<MenuTooltip width={200} onClose={onClose}>
<Menu
onMenuSelect={item => {
if (item === 'reconcile') {
setTooltip('reconcile');
} else {
onMenuSelect(item);
}
}}
items={[
isSorted && {
name: 'remove-sorting',
text: 'Remove all sorting',
},
canShowBalances && {
name: 'toggle-balance',
text: (showBalances ? 'Hide' : 'Show') + ' running balance',
},
{
name: 'toggle-cleared',
text: (showCleared ? 'Hide' : 'Show') + ' “cleared” checkboxes',
},
{
name: 'toggle-reconciled',
text:
(showReconciled ? 'Hide' : 'Show') + ' reconciled transactions',
},
{ name: 'export', text: 'Export' },
{ name: 'reconcile', text: 'Reconcile' },
account &&
!account.closed &&
(canSync
? {
name: 'unlink',
text: 'Unlink account',
}
: syncServerStatus === 'online' && {
name: 'link',
text: 'Link account',
}),
account.closed
? { name: 'reopen', text: 'Reopen account' }
: { name: 'close', text: 'Close account' },
].filter(x => x)}
/>
</MenuTooltip>
);
}
function CategoryMenu({ onClose, onMenuSelect, isSorted }) {
return (
<MenuTooltip width={200} onClose={onClose}>
<Menu
onMenuSelect={item => {
<Menu
onMenuSelect={item => {
if (item === 'reconcile') {
setTooltip('reconcile');
} else {
onMenuSelect(item);
}}
items={[
isSorted && {
name: 'remove-sorting',
text: 'Remove all sorting',
},
{ name: 'export', text: 'Export' },
]}
/>
</MenuTooltip>
}
}}
items={[
isSorted && {
name: 'remove-sorting',
text: 'Remove all sorting',
},
canShowBalances && {
name: 'toggle-balance',
text: (showBalances ? 'Hide' : 'Show') + ' running balance',
},
{
name: 'toggle-cleared',
text: (showCleared ? 'Hide' : 'Show') + ' “cleared” checkboxes',
},
{
name: 'toggle-reconciled',
text: (showReconciled ? 'Hide' : 'Show') + ' reconciled transactions',
},
{ name: 'export', text: 'Export' },
{ name: 'reconcile', text: 'Reconcile' },
account &&
!account.closed &&
(canSync
? {
name: 'unlink',
text: 'Unlink account',
}
: syncServerStatus === 'online' && {
name: 'link',
text: 'Link account',
}),
account.closed
? { name: 'reopen', text: 'Reopen account' }
: { name: 'close', text: 'Close account' },
].filter(x => x)}
/>
);
}
......@@ -12,7 +12,6 @@ import { Text } from '../common/Text';
import { View } from '../common/View';
import { useFormat } from '../spreadsheet/useFormat';
import { useSheetValue } from '../spreadsheet/useSheetValue';
import { Tooltip } from '../tooltips';
export function ReconcilingMessage({
balanceQuery,
......@@ -95,7 +94,7 @@ export function ReconcilingMessage({
);
}
export function ReconcileTooltip({ account, onReconcile, onClose }) {
export function ReconcileMenu({ account, onReconcile, onClose }) {
const balanceQuery = queries.accountBalance(account);
const clearedBalance = useSheetValue({
name: balanceQuery.name + '-cleared',
......@@ -117,24 +116,22 @@ export function ReconcileTooltip({ account, onReconcile, onClose }) {
}
return (
<Tooltip position="bottom-right" width={275} onClose={onClose}>
<View style={{ padding: '5px 8px' }}>
<Text>
Enter the current balance of your bank account that you want to
reconcile with:
</Text>
<form onSubmit={onSubmit}>
{clearedBalance != null && (
<InitialFocus>
<Input
defaultValue={format(clearedBalance, 'financial')}
style={{ margin: '7px 0' }}
/>
</InitialFocus>
)}
<Button type="primary">Reconcile</Button>
</form>
</View>
</Tooltip>
<View style={{ padding: '5px 8px' }}>
<Text>
Enter the current balance of your bank account that you want to
reconcile with:
</Text>
<form onSubmit={onSubmit}>
{clearedBalance != null && (
<InitialFocus>
<Input
defaultValue={format(clearedBalance, 'financial')}
style={{ margin: '7px 0' }}
/>
</InitialFocus>
)}
<Button type="primary">Reconcile</Button>
</form>
</View>
);
}
import { useCallback, useEffect, useState, type ReactNode } from 'react';
import { type CSSProperties } from '../../style';
import { View } from './View';
type HoverTargetProps = {
style?: CSSProperties;
contentStyle?: CSSProperties;
children: ReactNode;
renderContent: () => ReactNode;
disabled?: boolean;
};
export function HoverTarget({
style,
contentStyle,
children,
renderContent,
disabled,
}: HoverTargetProps) {
const [hovered, setHovered] = useState(false);
const onPointerEnter = useCallback(() => {
if (!disabled) {
setHovered(true);
}
}, [disabled]);
const onPointerLeave = useCallback(() => {
if (!disabled) {
setHovered(false);
}
}, [disabled]);
useEffect(() => {
if (disabled && hovered) {
setHovered(false);
}
}, [disabled, hovered]);
return (
<View style={style}>
<View
onPointerEnter={onPointerEnter}
onPointerLeave={onPointerLeave}
style={contentStyle}
>
{children}
</View>
{hovered && renderContent()}
</View>
);
}
import React, { type ReactNode } from 'react';
import { Tooltip } from '../tooltips';
type MenuTooltipProps = {
width: number;
onClose: () => void;
children: ReactNode;
};
export function MenuTooltip({ width, onClose, children }: MenuTooltipProps) {
return (
<Tooltip
position="bottom-right"
width={width}
style={{ padding: 0 }}
onClose={onClose}
>
{children}
</Tooltip>
);
}
......@@ -21,16 +21,15 @@ import {
import { titleFirst } from 'loot-core/src/shared/util';
import { useDateFormat } from '../../hooks/useDateFormat';
import { theme } from '../../style';
import { styles, theme } from '../../style';
import { Button } from '../common/Button';
import { HoverTarget } from '../common/HoverTarget';
import { Menu } from '../common/Menu';
import { Popover } from '../common/Popover';
import { Select } from '../common/Select';
import { Stack } from '../common/Stack';
import { Text } from '../common/Text';
import { Tooltip } from '../common/Tooltip';
import { View } from '../common/View';
import { Tooltip } from '../tooltips';
import { GenericInput } from '../util/GenericInput';
import { CompactFiltersButton } from './CompactFiltersButton';
......@@ -321,23 +320,17 @@ export function FilterButton({ onApply, compact, hover, exclude }) {
return (
<View>
<View ref={triggerRef}>
<HoverTarget
style={{ flexShrink: 0 }}
renderContent={() =>
hover && (
<Tooltip
position="bottom-left"
style={{
lineHeight: 1.5,
padding: '6px 10px',
backgroundColor: theme.menuBackground,
color: theme.menuItemText,
}}
>
<Text>Filters</Text>
</Tooltip>
)
}
<Tooltip
style={{
...styles.tooltip,
lineHeight: 1.5,
padding: '6px 10px',
}}
content={<Text>Filters</Text>}
placement="bottom start"
triggerProps={{
isDisabled: !hover,
}}
>
{compact ? (
<CompactFiltersButton
......@@ -346,7 +339,7 @@ export function FilterButton({ onApply, compact, hover, exclude }) {
) : (
<FiltersButton onClick={() => dispatch({ type: 'select-field' })} />
)}
</HoverTarget>
</Tooltip>
</View>
<Popover
......
......@@ -31,6 +31,7 @@ import { type CSSProperties, styles, theme } from '../style';
import { Button } from './common/Button';
import { Input } from './common/Input';
import { Menu } from './common/Menu';
import { Popover } from './common/Popover';
import { Text } from './common/Text';
import { View } from './common/View';
import { FixedSizeList } from './FixedSizeList';
......@@ -41,7 +42,7 @@ import {
import { type Binding } from './spreadsheet';
import { type FormatType, useFormat } from './spreadsheet/useFormat';
import { useSheetValue } from './spreadsheet/useSheetValue';
import { Tooltip, IntersectionBoundary } from './tooltips';
import { IntersectionBoundary } from './tooltips';
export const ROW_HEIGHT = 32;
......@@ -383,38 +384,24 @@ type InputCellProps = ComponentProps<typeof Cell> & {
onUpdate?: ComponentProps<typeof InputValue>['onUpdate'];
onBlur?: ComponentProps<typeof InputValue>['onBlur'];
textAlign?: CSSProperties['textAlign'];
error?: ReactNode;
};
export function InputCell({
inputProps,
onUpdate,
onBlur,
textAlign,
error,
...props
}: InputCellProps) {
return (
<Cell textAlign={textAlign} {...props}>
{() => (
<>
<InputValue
value={props.value}
onUpdate={onUpdate}
onBlur={onBlur}
style={{ textAlign, ...(inputProps && inputProps.style) }}
{...inputProps}
/>
{error && (
<Tooltip
key="error"
targetHeight={ROW_HEIGHT}
width={180}
position="bottom-left"
>
{error}
</Tooltip>
)}
</>
<InputValue
value={props.value}
onUpdate={onUpdate}
onBlur={onBlur}
style={{ textAlign, ...(inputProps && inputProps.style) }}
{...inputProps}
/>
)}
</Cell>
);
......@@ -809,6 +796,7 @@ export function TableHeader({
export function SelectedItemsButton({ name, items, onSelect }) {
const selectedItems = useSelectedItems();
const [menuOpen, setMenuOpen] = useState(null);
const triggerRef = useRef(null);
if (selectedItems.size === 0) {
return null;
......@@ -817,6 +805,7 @@ export function SelectedItemsButton({ name, items, onSelect }) {
return (
<View style={{ marginLeft: 10, flexShrink: 0 }}>
<Button
ref={triggerRef}
type="bare"
style={{ color: theme.pageTextPositive }}
onClick={() => setMenuOpen(true)}
......@@ -830,23 +819,25 @@ export function SelectedItemsButton({ name, items, onSelect }) {
{selectedItems.size} {name}
</Button>
{menuOpen && (
<Tooltip
position="bottom-right"
width={200}
style={{ padding: 0, backgroundColor: theme.menuBackground }}
onClose={() => setMenuOpen(false)}
data-testid={name + '-select-tooltip'}
>
<Menu
onMenuSelect={name => {
onSelect(name, [...selectedItems]);
setMenuOpen(false);
}}
items={items}
/>
</Tooltip>
)}
<Popover
triggerRef={triggerRef}
style={{
width: 200,
padding: 0,
backgroundColor: theme.menuBackground,
}}
isOpen={menuOpen}
onOpenChange={() => setMenuOpen(false)}
data-testid={name + '-select-tooltip'}
>
<Menu
onMenuSelect={name => {
onSelect(name, [...selectedItems]);
setMenuOpen(false);
}}
items={items}
/>
</Popover>
</View>
);
}
......
---
category: Maintenance
authors: [MatissJanis]
---
Migrating native `Tooltip` component to react-aria Tooltip/Popover (vol.9)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment