diff --git a/packages/desktop-client/src/components/accounts/Account.jsx b/packages/desktop-client/src/components/accounts/Account.jsx index 06fddb35e6a521ca3a782b55d30ba2dea7768a09..3153fd749fa3bd69450fa8392bff51830695b916 100644 --- a/packages/desktop-client/src/components/accounts/Account.jsx +++ b/packages/desktop-client/src/components/accounts/Account.jsx @@ -75,7 +75,12 @@ function EmptyMessage({ onAdd }) { manage it locally yourself. </Text> - <Button variant="primary" style={{ marginTop: 20 }} onPress={onAdd}> + <Button + variant="primary" + style={{ marginTop: 20 }} + autoFocus + onPress={onAdd} + > Add account </Button> diff --git a/packages/desktop-client/src/components/accounts/AccountSyncCheck.jsx b/packages/desktop-client/src/components/accounts/AccountSyncCheck.jsx index 046f047eb5144e2e16870f90c2ccb03241aa6330..e8812ecadac81d9b1aa5b06526e2128e526cb827 100644 --- a/packages/desktop-client/src/components/accounts/AccountSyncCheck.jsx +++ b/packages/desktop-client/src/components/accounts/AccountSyncCheck.jsx @@ -140,6 +140,7 @@ export function AccountSyncCheck() { <Button onPress={unlink}>Unlink</Button> <Button variant="primary" + autoFocus onPress={reauth} style={{ marginLeft: 5 }} > diff --git a/packages/desktop-client/src/components/accounts/Reconcile.jsx b/packages/desktop-client/src/components/accounts/Reconcile.jsx index ab7127858ef6008f9e23480586f63c53fd5c9231..5ebcd31fa76ab769f90959179a85246a7033b655 100644 --- a/packages/desktop-client/src/components/accounts/Reconcile.jsx +++ b/packages/desktop-client/src/components/accounts/Reconcile.jsx @@ -78,7 +78,7 @@ export function ReconcilingMessage({ </View> )} <View style={{ marginLeft: 15 }}> - <Button variant="primary" onPress={onDone}> + <Button variant="primary" autoFocus onPress={onDone}> Done Reconciling </Button> </View> diff --git a/packages/desktop-client/src/components/manager/ImportActual.tsx b/packages/desktop-client/src/components/manager/ImportActual.tsx index 360f7d7a4152ec8b5146dde9851f6c920af877d8..78305fdeb3a94de4fc694e0570e51bad658cf55d 100644 --- a/packages/desktop-client/src/components/manager/ImportActual.tsx +++ b/packages/desktop-client/src/components/manager/ImportActual.tsx @@ -84,6 +84,7 @@ export function ImportActual({ modalProps }: ImportProps) { <View style={{ alignSelf: 'center' }}> <ButtonWithLoading variant="primary" + autoFocus isLoading={importing} onPress={onImport} > diff --git a/packages/desktop-client/src/components/manager/ImportYNAB4.tsx b/packages/desktop-client/src/components/manager/ImportYNAB4.tsx index e145977c8688c774e693a0a145dc85c9379b412e..b0a8478baef292e63b63f8f9259eaf13fc1f31ad 100644 --- a/packages/desktop-client/src/components/manager/ImportYNAB4.tsx +++ b/packages/desktop-client/src/components/manager/ImportYNAB4.tsx @@ -73,6 +73,7 @@ export function ImportYNAB4({ modalProps }: ImportProps) { <View> <ButtonWithLoading variant="primary" + autoFocus isLoading={importing} onPress={onImport} > diff --git a/packages/desktop-client/src/components/manager/ImportYNAB5.tsx b/packages/desktop-client/src/components/manager/ImportYNAB5.tsx index 3876f337a55b947d0c3c14ec50cdae82e7c8f209..5771e99c99cc8d855cc28909f82ae0a8899f6402 100644 --- a/packages/desktop-client/src/components/manager/ImportYNAB5.tsx +++ b/packages/desktop-client/src/components/manager/ImportYNAB5.tsx @@ -83,6 +83,7 @@ export function ImportYNAB5({ modalProps }: ImportProps) { <View> <ButtonWithLoading variant="primary" + autoFocus isLoading={importing} onPress={onImport} > diff --git a/packages/desktop-client/src/components/manager/WelcomeScreen.tsx b/packages/desktop-client/src/components/manager/WelcomeScreen.tsx index 8dcc9f4f3aec63651dff493a325926f94c65b61a..71fda245e06d59b03944552f4546234e5b501e8a 100644 --- a/packages/desktop-client/src/components/manager/WelcomeScreen.tsx +++ b/packages/desktop-client/src/components/manager/WelcomeScreen.tsx @@ -90,7 +90,7 @@ export function WelcomeScreen() { <Button onPress={() => createBudget({ testMode: true })}> {t('View demo')} </Button> - <Button variant="primary" onPress={() => createBudget()}> + <Button variant="primary" autoFocus onPress={() => createBudget()}> {t('Start fresh')} </Button> </View> diff --git a/packages/desktop-client/src/components/mobile/transactions/TransactionEdit.jsx b/packages/desktop-client/src/components/mobile/transactions/TransactionEdit.jsx index f80218f6bfaf2a5473d82c3dd4644d67a8c81454..3cb7db7644b30284a644085e9d37a60be96499e4 100644 --- a/packages/desktop-client/src/components/mobile/transactions/TransactionEdit.jsx +++ b/packages/desktop-client/src/components/mobile/transactions/TransactionEdit.jsx @@ -460,7 +460,7 @@ const TransactionEditInner = memo(function TransactionEditInner({ const { editingField, onRequestActiveEdit, onClearActiveEdit } = useSingleActiveEditForm(); - const [totalAmountFocused, setTotalAmountFocused] = useState(false); + const [totalAmountFocused, setTotalAmountFocused] = useState(true); const childTransactionElementRefMap = useRef({}); const payeesById = useMemo(() => groupById(payees), [payees]); diff --git a/packages/desktop-client/src/components/modals/CloseAccountModal.tsx b/packages/desktop-client/src/components/modals/CloseAccountModal.tsx index c1668a70105217f8da6455c7f9436b4ac85b535b..c51ec6dbaac2dc2125e3642c9a55f9675990e945 100644 --- a/packages/desktop-client/src/components/modals/CloseAccountModal.tsx +++ b/packages/desktop-client/src/components/modals/CloseAccountModal.tsx @@ -151,6 +151,7 @@ export function CloseAccountModal({ value={transferAccountId} inputProps={{ placeholder: 'Select account...', + autoFocus: true, ...(isNarrowWidth && { value: transferAccount?.name || '', style: { diff --git a/packages/desktop-client/src/components/modals/ConfirmCategoryDelete.tsx b/packages/desktop-client/src/components/modals/ConfirmCategoryDelete.tsx index 7713a6a09ffdbbe8f421ae6d2bdd1624a3a4dc00..d1191938f4797932fb64756cac09d8efa66b7df5 100644 --- a/packages/desktop-client/src/components/modals/ConfirmCategoryDelete.tsx +++ b/packages/desktop-client/src/components/modals/ConfirmCategoryDelete.tsx @@ -67,7 +67,7 @@ export function ConfirmCategoryDelete({ {group ? ( <Block> Categories in the group <strong>{group.name}</strong> are used - by existing transaction + by existing transactions {!isIncome && ' or it has a positive leftover balance currently'} . <strong>Are you sure you want to delete it?</strong> If so, @@ -115,6 +115,7 @@ export function ConfirmCategoryDelete({ })) } value={transferCategory} + focused={true} inputProps={{ placeholder: 'Select category...', }} diff --git a/packages/desktop-client/src/components/modals/ConfirmTransactionDelete.tsx b/packages/desktop-client/src/components/modals/ConfirmTransactionDelete.tsx index 26f2ecaf230811e369b48ebd1374dfe344e492cb..7c1b43ef83275b83e50a2ca9501bad81913d32ab 100644 --- a/packages/desktop-client/src/components/modals/ConfirmTransactionDelete.tsx +++ b/packages/desktop-client/src/components/modals/ConfirmTransactionDelete.tsx @@ -3,6 +3,7 @@ import React from 'react'; import { useResponsive } from '../../ResponsiveProvider'; import { styles } from '../../style'; import { Button } from '../common/Button2'; +import { InitialFocus } from '../common/InitialFocus'; import { Modal, ModalCloseButton, ModalHeader } from '../common/Modal2'; import { Paragraph } from '../common/Paragraph'; import { View } from '../common/View'; @@ -48,16 +49,18 @@ export function ConfirmTransactionDelete({ > Cancel </Button> - <Button - variant="primary" - style={narrowButtonStyle} - onPress={() => { - onConfirm(); - close(); - }} - > - Delete - </Button> + <InitialFocus> + <Button + variant="primary" + style={narrowButtonStyle} + onPress={() => { + onConfirm(); + close(); + }} + > + Delete + </Button> + </InitialFocus> </View> </View> </> diff --git a/packages/desktop-client/src/components/modals/ConfirmTransactionEdit.tsx b/packages/desktop-client/src/components/modals/ConfirmTransactionEdit.tsx index 6b445bda669085eec147f9d2289130fdf192d071..4d456859145ada46cc7f08398a21e13744050a17 100644 --- a/packages/desktop-client/src/components/modals/ConfirmTransactionEdit.tsx +++ b/packages/desktop-client/src/components/modals/ConfirmTransactionEdit.tsx @@ -3,6 +3,7 @@ import React from 'react'; import { Block } from '../common/Block'; import { Button } from '../common/Button2'; +import { InitialFocus } from '../common/InitialFocus'; import { Modal, ModalCloseButton, ModalHeader } from '../common/Modal2'; import { View } from '../common/View'; @@ -88,16 +89,18 @@ export function ConfirmTransactionEdit({ > Cancel </Button> - <Button - aria-label="Confirm" - variant="primary" - onPress={() => { - close(); - onConfirm(); - }} - > - Confirm - </Button> + <InitialFocus> + <Button + aria-label="Confirm" + variant="primary" + onPress={() => { + close(); + onConfirm(); + }} + > + Confirm + </Button> + </InitialFocus> </View> </View> </View> diff --git a/packages/desktop-client/src/components/modals/ConfirmUnlinkAccount.tsx b/packages/desktop-client/src/components/modals/ConfirmUnlinkAccount.tsx index e3d5fb53595935c4ecfcf93cd0fed864028fa59d..6a51ded8ba398fcb9deea2619759b36bc9ec17f0 100644 --- a/packages/desktop-client/src/components/modals/ConfirmUnlinkAccount.tsx +++ b/packages/desktop-client/src/components/modals/ConfirmUnlinkAccount.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { Button } from '../common/Button2'; +import { InitialFocus } from '../common/InitialFocus'; import { Modal, ModalCloseButton, ModalHeader } from '../common/Modal2'; import { Paragraph } from '../common/Paragraph'; import { View } from '../common/View'; @@ -44,15 +45,17 @@ export function ConfirmUnlinkAccount({ <Button style={{ marginRight: 10 }} onPress={close}> Cancel </Button> - <Button - variant="primary" - onPress={() => { - onUnlink(); - close(); - }} - > - Unlink - </Button> + <InitialFocus> + <Button + variant="primary" + onPress={() => { + onUnlink(); + close(); + }} + > + Unlink + </Button> + </InitialFocus> </View> </View> </> diff --git a/packages/desktop-client/src/components/modals/CreateAccountModal.tsx b/packages/desktop-client/src/components/modals/CreateAccountModal.tsx index c23e67aaf2e3d001502f70e9e610c807fd0c58e2..ed88da037aafb3f5ec317f54e57ac3b926c7e322 100644 --- a/packages/desktop-client/src/components/modals/CreateAccountModal.tsx +++ b/packages/desktop-client/src/components/modals/CreateAccountModal.tsx @@ -12,6 +12,7 @@ import { type SyncServerStatus } from '../../hooks/useSyncServerStatus'; import { SvgDotsHorizontalTriple } from '../../icons/v1'; import { theme } from '../../style'; import { Button, ButtonWithLoading } from '../common/Button2'; +import { InitialFocus } from '../common/InitialFocus'; import { Link } from '../common/Link'; import { Menu } from '../common/Menu'; import { Modal, ModalCloseButton, ModalHeader } from '../common/Modal2'; @@ -186,17 +187,19 @@ export function CreateAccountModal({ <View style={{ maxWidth: 500, gap: 30, color: theme.pageText }}> {upgradingAccountId == null && ( <View style={{ gap: 10 }}> - <Button - variant="primary" - style={{ - padding: '10px 0', - fontSize: 15, - fontWeight: 600, - }} - onPress={onCreateLocalAccount} - > - Create local account - </Button> + <InitialFocus> + <Button + variant="primary" + style={{ + padding: '10px 0', + fontSize: 15, + fontWeight: 600, + }} + onPress={onCreateLocalAccount} + > + Create local account + </Button> + </InitialFocus> <View style={{ lineHeight: '1.4em', fontSize: 15 }}> <Text> <strong>Create a local account</strong> if you want to add diff --git a/packages/desktop-client/src/components/modals/GoCardlessExternalMsg.tsx b/packages/desktop-client/src/components/modals/GoCardlessExternalMsg.tsx index 2dbbc049eefbb2841f4c3572ac0fb743ee372b1b..ef3bef944b5f8fea7f9b33492af89abb9a191f93 100644 --- a/packages/desktop-client/src/components/modals/GoCardlessExternalMsg.tsx +++ b/packages/desktop-client/src/components/modals/GoCardlessExternalMsg.tsx @@ -206,6 +206,7 @@ export function GoCardlessExternalMsg({ <View style={{ flexDirection: 'row', gap: 10, alignItems: 'center' }}> <Button variant="primary" + autoFocus style={{ padding: '10px 0', fontSize: 15, @@ -272,6 +273,7 @@ export function GoCardlessExternalMsg({ ) : success ? ( <Button variant="primary" + autoFocus style={{ padding: '10px 0', fontSize: 15, diff --git a/packages/desktop-client/src/components/modals/GoCardlessInitialise.tsx b/packages/desktop-client/src/components/modals/GoCardlessInitialise.tsx index fc91a66a1a9627145043d75d5f71bf115fa1973d..6906b26c8366cd53f80264ed028efcfb619108c5 100644 --- a/packages/desktop-client/src/components/modals/GoCardlessInitialise.tsx +++ b/packages/desktop-client/src/components/modals/GoCardlessInitialise.tsx @@ -5,6 +5,7 @@ import { send } from 'loot-core/src/platform/client/fetch'; import { Error } from '../alerts'; import { ButtonWithLoading } from '../common/Button2'; +import { InitialFocus } from '../common/InitialFocus'; import { Input } from '../common/Input'; import { Link } from '../common/Link'; import { @@ -78,15 +79,17 @@ export const GoCardlessInitialise = ({ <FormField> <FormLabel title="Secret ID:" htmlFor="secret-id-field" /> - <Input - id="secret-id-field" - type="password" - value={secretId} - onChangeValue={value => { - setSecretId(value); - setIsValid(true); - }} - /> + <InitialFocus> + <Input + id="secret-id-field" + type="password" + value={secretId} + onChangeValue={value => { + setSecretId(value); + setIsValid(true); + }} + /> + </InitialFocus> </FormField> <FormField> diff --git a/packages/desktop-client/src/components/modals/ImportTransactions.jsx b/packages/desktop-client/src/components/modals/ImportTransactions.jsx index 88ffb478855d54b895ebcf077baf5d322b73448a..d3f281a59fc4e6a61f944d4e7bed2da31c31ef5b 100644 --- a/packages/desktop-client/src/components/modals/ImportTransactions.jsx +++ b/packages/desktop-client/src/components/modals/ImportTransactions.jsx @@ -1719,6 +1719,7 @@ export function ImportTransactions({ options }) { > <ButtonWithLoading variant="primary" + autoFocus isDisabled={ transactions?.filter(trans => !trans.isMatchedTransaction) .length === 0 diff --git a/packages/desktop-client/src/components/modals/MergeUnusedPayees.jsx b/packages/desktop-client/src/components/modals/MergeUnusedPayees.jsx index 2a82568695ad9667f3bb3ddf6d9f1c58b8566a48..0b236b5982d4b49b4c9930c773d0891f842739e5 100644 --- a/packages/desktop-client/src/components/modals/MergeUnusedPayees.jsx +++ b/packages/desktop-client/src/components/modals/MergeUnusedPayees.jsx @@ -151,6 +151,7 @@ export function MergeUnusedPayees({ payeeIds, targetPayeeId }) { <ModalButtons style={{ marginTop: 20 }} focusButton> <Button variant="primary" + autoFocus style={{ marginRight: 10 }} onPress={() => { onMerge(); diff --git a/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx b/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx index 21613af5c1f690e6751bd06c5c8ee75e52a7cc3c..f6587c7269cca98154c5b32cd709414b1b8d75b6 100644 --- a/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx +++ b/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx @@ -88,6 +88,7 @@ export const SimpleFinInitialise = ({ <ModalButtons> <ButtonWithLoading variant="primary" + autoFocus isLoading={isLoading} onPress={() => { onSubmit(close); diff --git a/packages/desktop-client/src/components/reports/SaveReportDelete.tsx b/packages/desktop-client/src/components/reports/SaveReportDelete.tsx index 7a8da58a5bb5466d9f2bcd2a2a30d49c50ab8396..436b3ef95fb61007dd1caa748e7043bb47ca04d3 100644 --- a/packages/desktop-client/src/components/reports/SaveReportDelete.tsx +++ b/packages/desktop-client/src/components/reports/SaveReportDelete.tsx @@ -21,7 +21,7 @@ export function SaveReportDelete({ <> <View style={{ align: 'center' }}> <Text style={{ color: theme.errorText, marginBottom: 5 }}> - Do you want to delete report: + Are you sure you want to delete report: </Text> <View>{name}</View> </View> @@ -33,7 +33,7 @@ export function SaveReportDelete({ style={{ marginTop: 15 }} > <View style={{ flex: 1 }} /> - <Button variant="primary" onPress={onDelete}> + <Button variant="primary" autoFocus onPress={onDelete}> Yes </Button> <Button variant="primary" onPress={onClose}> diff --git a/packages/desktop-client/src/components/schedules/PostsOfflineNotification.jsx b/packages/desktop-client/src/components/schedules/PostsOfflineNotification.jsx index b19c0dc9e503ed648ce4b1fb19f06b28f4d1e364..29ad0f5da3894b60357b4b17dfb6345e2a6d4bab 100644 --- a/packages/desktop-client/src/components/schedules/PostsOfflineNotification.jsx +++ b/packages/desktop-client/src/components/schedules/PostsOfflineNotification.jsx @@ -81,6 +81,7 @@ export function PostsOfflineNotification() { <Button onPress={close}>Decide later</Button> <Button variant="primary" + autoFocus onPress={() => { onPost(); close(); diff --git a/packages/desktop-client/src/components/schedules/ScheduleDetails.jsx b/packages/desktop-client/src/components/schedules/ScheduleDetails.jsx index a91aeb3b6d06fa6469a4149d42c94073acde953a..67900bf27b907468dd4ec253d62f7486026f9e97 100644 --- a/packages/desktop-client/src/components/schedules/ScheduleDetails.jsx +++ b/packages/desktop-client/src/components/schedules/ScheduleDetails.jsx @@ -18,6 +18,7 @@ import { theme } from '../../style'; import { AccountAutocomplete } from '../autocomplete/AccountAutocomplete'; import { PayeeAutocomplete } from '../autocomplete/PayeeAutocomplete'; import { Button } from '../common/Button2'; +import { InitialFocus } from '../common/InitialFocus'; import { Modal, ModalCloseButton, ModalHeader } from '../common/Modal2'; import { Stack } from '../common/Stack'; import { Text } from '../common/Text'; @@ -462,15 +463,17 @@ export function ScheduleDetails({ id, transaction }) { <Stack direction="row" style={{ marginTop: 10 }}> <FormField style={{ flex: 1 }}> <FormLabel title="Schedule Name" htmlFor="name-field" /> - <GenericInput - field="string" - type="string" - value={state.fields.name} - multi={false} - onChange={e => { - dispatch({ type: 'set-field', field: 'name', value: e }); - }} - /> + <InitialFocus> + <GenericInput + field="string" + type="string" + value={state.fields.name} + multi={false} + onChange={e => { + dispatch({ type: 'set-field', field: 'name', value: e }); + }} + /> + </InitialFocus> </FormField> </Stack> <Stack direction="row" style={{ marginTop: 20 }}> diff --git a/packages/desktop-client/src/components/schedules/ScheduleLink.tsx b/packages/desktop-client/src/components/schedules/ScheduleLink.tsx index 74d22edd7b490b9ef352053d1ec817c478415064..15b3409a75fa827af25074900bc095feb8a50689 100644 --- a/packages/desktop-client/src/components/schedules/ScheduleLink.tsx +++ b/packages/desktop-client/src/components/schedules/ScheduleLink.tsx @@ -13,6 +13,7 @@ import { import { SvgAdd } from '../../icons/v0'; import { Button } from '../common/Button2'; +import { InitialFocus } from '../common/InitialFocus'; import { Modal, ModalCloseButton, ModalHeader } from '../common/Modal2'; import { Search } from '../common/Search'; import { Text } from '../common/Text'; @@ -93,14 +94,16 @@ export function ScheduleLink({ : `this transaction belongs`}{' '} to: </Text> - <Search - inputRef={searchInput} - isInModal - width={300} - placeholder="Filter schedules…" - value={filter} - onChange={setFilter} - /> + <InitialFocus> + <Search + inputRef={searchInput} + isInModal + width={300} + placeholder="Filter schedules…" + value={filter} + onChange={setFilter} + /> + </InitialFocus> {ids.length === 1 && ( <Button variant="primary" diff --git a/packages/desktop-client/src/components/select/RecurringSchedulePicker.jsx b/packages/desktop-client/src/components/select/RecurringSchedulePicker.jsx index 20244423f917711a611bb80f7bbe65d250927950..036b875c8875f440f844781b023fdf851ea96df8 100644 --- a/packages/desktop-client/src/components/select/RecurringSchedulePicker.jsx +++ b/packages/desktop-client/src/components/select/RecurringSchedulePicker.jsx @@ -8,6 +8,7 @@ import { useDateFormat } from '../../hooks/useDateFormat'; import { SvgAdd, SvgSubtract } from '../../icons/v0'; import { theme } from '../../style'; import { Button } from '../common/Button2'; +import { InitialFocus } from '../common/InitialFocus'; import { Input } from '../common/Input'; import { Menu } from '../common/Menu'; import { Popover } from '../common/Popover'; @@ -310,14 +311,16 @@ function RecurringScheduleTooltip({ config: currentConfig, onClose, onSave }) { <> <div style={{ display: 'flex', alignItems: 'center', gap: 5 }}> <label htmlFor="start">From</label> - <DateSelect - id="start" - inputProps={{ placeholder: 'Start Date' }} - value={config.start} - onSelect={value => updateField('start', value)} - containerProps={{ style: { width: 100 } }} - dateFormat={dateFormat} - /> + <InitialFocus> + <DateSelect + id="start" + inputProps={{ placeholder: 'Start Date' }} + value={config.start} + onSelect={value => updateField('start', value)} + containerProps={{ style: { width: 100 } }} + dateFormat={dateFormat} + /> + </InitialFocus> <Select id="repeat_end_dropdown" options={[ diff --git a/upcoming-release-notes/2974.md b/upcoming-release-notes/2974.md new file mode 100644 index 0000000000000000000000000000000000000000..ec647222032bd4c62e0ccf4d4819a9d584dee649 --- /dev/null +++ b/upcoming-release-notes/2974.md @@ -0,0 +1,6 @@ +--- +category: Bugfix +authors: [psybers] +--- + +Fix: Automatically focus inputs, or the primary button, in modals.