mirror of
https://github.com/actualbudget/actual.git
synced 2026-03-11 17:47:00 -05:00
Pull shiftKey state directly from the initiating event (#1022)
Fixes #1021
This commit is contained in:
@@ -329,8 +329,8 @@ let Rule = memo(
|
||||
<SelectCell
|
||||
exposed={hovered || selected || editing}
|
||||
focused={focusedField === 'select'}
|
||||
onSelect={() => {
|
||||
dispatchSelected({ type: 'select', id: rule.id });
|
||||
onSelect={e => {
|
||||
dispatchSelected({ type: 'select', id: rule.id, event: e });
|
||||
}}
|
||||
onEdit={() => onEdit(rule.id, 'select')}
|
||||
selected={selected}
|
||||
@@ -478,7 +478,7 @@ function RulesHeader() {
|
||||
exposed={true}
|
||||
focused={false}
|
||||
selected={selectedItems.size > 0}
|
||||
onSelect={() => dispatchSelected({ type: 'select-all' })}
|
||||
onSelect={e => dispatchSelected({ type: 'select-all', event: e })}
|
||||
/>
|
||||
<Cell value="Stage" width={50} />
|
||||
<Cell value="Rule" width="flex" />
|
||||
|
||||
@@ -51,8 +51,8 @@ const TransactionRow = memo(function TransactionRow({
|
||||
<SelectCell
|
||||
exposed={true}
|
||||
focused={false}
|
||||
onSelect={() => {
|
||||
dispatchSelected({ type: 'select', id: transaction.id });
|
||||
onSelect={e => {
|
||||
dispatchSelected({ type: 'select', id: transaction.id, event: e });
|
||||
}}
|
||||
selected={selected}
|
||||
/>
|
||||
@@ -185,7 +185,7 @@ export default function SimpleTransactionsTable({
|
||||
focused={false}
|
||||
selected={selectedItems.size > 0}
|
||||
width={20}
|
||||
onSelect={() => dispatchSelected({ type: 'select-all' })}
|
||||
onSelect={e => dispatchSelected({ type: 'select-all', event: e })}
|
||||
/>
|
||||
{fields.map((field, i) => {
|
||||
switch (field) {
|
||||
|
||||
@@ -255,7 +255,7 @@ export const TransactionHeader = memo(
|
||||
focused={false}
|
||||
selected={hasSelected}
|
||||
width={20}
|
||||
onSelect={() => dispatchSelected({ type: 'select-all' })}
|
||||
onSelect={e => dispatchSelected({ type: 'select-all', event: e })}
|
||||
/>
|
||||
<Cell value="Date" width={110} />
|
||||
{showAccount && <Cell value="Account" width="flex" />}
|
||||
@@ -690,8 +690,8 @@ export const Transaction = memo(function Transaction(props) {
|
||||
<SelectCell
|
||||
exposed={hovered || selected || editing}
|
||||
focused={focusedField === 'select'}
|
||||
onSelect={() => {
|
||||
dispatchSelected({ type: 'select', id: transaction.id });
|
||||
onSelect={e => {
|
||||
dispatchSelected({ type: 'select', id: transaction.id, event: e });
|
||||
}}
|
||||
onEdit={() => onEdit(id, 'select')}
|
||||
selected={selected}
|
||||
|
||||
@@ -138,8 +138,8 @@ let Payee = memo(
|
||||
}
|
||||
focused={focusedField === 'select'}
|
||||
selected={selected}
|
||||
onSelect={() => {
|
||||
dispatchSelected({ type: 'select', id: payee.id });
|
||||
onSelect={e => {
|
||||
dispatchSelected({ type: 'select', id: payee.id, event: e });
|
||||
}}
|
||||
/>
|
||||
<InputCell
|
||||
@@ -247,7 +247,7 @@ function PayeeTableHeader() {
|
||||
exposed={true}
|
||||
focused={false}
|
||||
selected={selectedItems.size > 0}
|
||||
onSelect={() => dispatchSelected({ type: 'select-all' })}
|
||||
onSelect={e => dispatchSelected({ type: 'select-all', event: e })}
|
||||
/>
|
||||
<Cell value="Name" width="flex" />
|
||||
</TableHeader>
|
||||
|
||||
@@ -35,8 +35,8 @@ function DiscoverSchedulesTable({ schedules, loading }) {
|
||||
height={ROW_HEIGHT}
|
||||
inset={15}
|
||||
backgroundColor="transparent"
|
||||
onClick={() => {
|
||||
dispatchSelected({ type: 'select', id: item.id });
|
||||
onClick={e => {
|
||||
dispatchSelected({ type: 'select', id: item.id, event: e });
|
||||
}}
|
||||
borderColor={selected ? colors.b8 : colors.border}
|
||||
style={{
|
||||
@@ -51,8 +51,8 @@ function DiscoverSchedulesTable({ schedules, loading }) {
|
||||
exposed={true}
|
||||
focused={false}
|
||||
selected={selected}
|
||||
onSelect={() => {
|
||||
dispatchSelected({ type: 'select', id: item.id });
|
||||
onSelect={e => {
|
||||
dispatchSelected({ type: 'select', id: item.id, event: e });
|
||||
}}
|
||||
/>
|
||||
<Field width="flex">
|
||||
@@ -76,7 +76,7 @@ function DiscoverSchedulesTable({ schedules, loading }) {
|
||||
exposed={true}
|
||||
focused={false}
|
||||
selected={selectedItems.size > 0}
|
||||
onSelect={() => dispatchSelected({ type: 'select-all' })}
|
||||
onSelect={e => dispatchSelected({ type: 'select-all', event: e })}
|
||||
/>
|
||||
<Field width="flex">Payee</Field>
|
||||
<Field width="flex">Account</Field>
|
||||
|
||||
@@ -491,7 +491,7 @@ export const CellButton = forwardRef(
|
||||
if (e.key === 'x' || e.key === ' ') {
|
||||
e.preventDefault();
|
||||
if (!disabled) {
|
||||
onSelect && onSelect();
|
||||
onSelect && onSelect(e);
|
||||
}
|
||||
}
|
||||
}}
|
||||
@@ -513,9 +513,9 @@ export const CellButton = forwardRef(
|
||||
onClick={
|
||||
clickBehavior === 'none'
|
||||
? null
|
||||
: () => {
|
||||
: e => {
|
||||
if (!disabled) {
|
||||
onSelect && onSelect();
|
||||
onSelect && onSelect(e);
|
||||
onEdit && onEdit();
|
||||
}
|
||||
}
|
||||
@@ -545,7 +545,7 @@ export function SelectCell({
|
||||
style={[{ alignItems: 'center', userSelect: 'none' }, style]}
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
onSelect && onSelect();
|
||||
onSelect && onSelect(e);
|
||||
onEdit && onEdit();
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -10,8 +10,7 @@ import { useSelector } from 'react-redux';
|
||||
|
||||
import { listen } from 'loot-core/src/platform/client/fetch';
|
||||
import * as undo from 'loot-core/src/platform/client/undo';
|
||||
|
||||
import { hasModifierKey } from '../util/keys';
|
||||
import { isNonProductionEnvironment } from 'loot-core/src/shared/environment';
|
||||
|
||||
function iterateRange(range, func) {
|
||||
let from = Math.min(range.start, range.end);
|
||||
@@ -29,9 +28,9 @@ export default function useSelected(name, items, initialSelectedIds) {
|
||||
case 'select': {
|
||||
let { selectedRange } = state;
|
||||
let selectedItems = new Set(state.selectedItems);
|
||||
let { id } = action;
|
||||
let { id, event } = action;
|
||||
|
||||
if (hasModifierKey('shift') && selectedRange) {
|
||||
if (event.shiftKey && selectedRange) {
|
||||
let idx = items.findIndex(p => p.id === id);
|
||||
let startIdx = items.findIndex(p => p.id === selectedRange.start);
|
||||
let endIdx = items.findIndex(p => p.id === selectedRange.end);
|
||||
@@ -224,17 +223,24 @@ export function SelectedProvider({ instance, fetchAllIds, children }) {
|
||||
|
||||
let dispatch = useCallback(
|
||||
async action => {
|
||||
if (!action.event && isNonProductionEnvironment()) {
|
||||
throw new Error('SelectedDispatch actions must have an event');
|
||||
}
|
||||
if (action.type === 'select-all') {
|
||||
if (latestItems.current && latestItems.current.size > 0) {
|
||||
return instance.dispatch({ type: 'select-none' });
|
||||
return instance.dispatch({
|
||||
type: 'select-none',
|
||||
event: action.event,
|
||||
});
|
||||
} else {
|
||||
if (fetchAllIds) {
|
||||
return instance.dispatch({
|
||||
type: 'select-all',
|
||||
ids: await fetchAllIds(),
|
||||
event: action.event,
|
||||
});
|
||||
}
|
||||
return instance.dispatch({ type: 'select-all' });
|
||||
return instance.dispatch({ type: 'select-all', event: action.event });
|
||||
}
|
||||
}
|
||||
return instance.dispatch(action);
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
// TODO: This is a barebones module for now, need to think about a
|
||||
// generic way keys are handled across the app
|
||||
|
||||
let _keyHandlers = {};
|
||||
|
||||
let _modifierState = {
|
||||
shift: false,
|
||||
ctrl: false,
|
||||
alt: false,
|
||||
meta: false,
|
||||
};
|
||||
|
||||
export function hasModifierKey(modifier) {
|
||||
return !!_modifierState[modifier];
|
||||
}
|
||||
|
||||
export function registerKeyHandler(key, func) {
|
||||
if (!_keyHandlers[key]) {
|
||||
_keyHandlers[key] = [];
|
||||
}
|
||||
_keyHandlers[key].push(func);
|
||||
|
||||
return () => {
|
||||
_keyHandlers[key] = _keyHandlers[key].filter(f => f !== func);
|
||||
};
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', e => {
|
||||
if (e.key === 'Shift') {
|
||||
_modifierState.shift = true;
|
||||
}
|
||||
if (e.key === 'Control') {
|
||||
_modifierState.ctrl = true;
|
||||
}
|
||||
if (e.key === 'Alt') {
|
||||
_modifierState.alt = true;
|
||||
}
|
||||
if (e.key === 'Meta') {
|
||||
_modifierState.meta = true;
|
||||
}
|
||||
|
||||
if (!(e.target && e.target.matches('input'))) {
|
||||
let handlers = _keyHandlers[e.key.toUpperCase()];
|
||||
if (handlers && handlers.length > 0) {
|
||||
handlers[handlers.length - 1](_modifierState);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('keyup', e => {
|
||||
if (e.key === 'Shift') {
|
||||
_modifierState.shift = false;
|
||||
}
|
||||
if (e.key === 'Control') {
|
||||
_modifierState.ctrl = false;
|
||||
}
|
||||
if (e.key === 'Alt') {
|
||||
_modifierState.alt = false;
|
||||
}
|
||||
if (e.key === 'Meta') {
|
||||
_modifierState.meta = false;
|
||||
}
|
||||
});
|
||||
6
upcoming-release-notes/1022.md
Normal file
6
upcoming-release-notes/1022.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: Maintenance
|
||||
authors: [j-f1]
|
||||
---
|
||||
|
||||
Improve behavior of shift-clicking checkboxes to select multiple transactions.
|
||||
Reference in New Issue
Block a user