From c2e648c9d5436f3d08449cfee032ef59411ca3de Mon Sep 17 00:00:00 2001 From: Joel Jeremy Marquez <joeljeremy.marquez@gmail.com> Date: Wed, 17 Jul 2024 13:38:41 -0700 Subject: [PATCH] React Aria Button on Modals (#2918) * React Aria Button on modals * Release notes * Remove tabIndex * Remove aria-label --- .../components/modals/AccountMenuModal.tsx | 8 +- .../modals/CategoryGroupMenuModal.tsx | 10 +-- .../components/modals/CategoryMenuModal.tsx | 8 +- .../components/modals/CloseAccountModal.tsx | 59 +++++++------- .../modals/ConfirmCategoryDelete.tsx | 6 +- .../modals/ConfirmTransactionDelete.tsx | 8 +- .../modals/ConfirmTransactionEdit.tsx | 8 +- .../modals/ConfirmUnlinkAccount.tsx | 8 +- .../src/components/modals/CoverModal.tsx | 6 +- .../components/modals/CreateAccountModal.tsx | 30 +++---- .../modals/CreateEncryptionKeyModal.tsx | 6 +- .../modals/CreateLocalAccountModal.tsx | 56 +++++++------ .../src/components/modals/EditField.jsx | 8 +- .../src/components/modals/EditRule.jsx | 34 ++++---- .../modals/FixEncryptionKeyModal.tsx | 17 ++-- .../modals/GoCardlessExternalMsg.tsx | 14 ++-- .../modals/GoCardlessInitialise.tsx | 8 +- .../src/components/modals/HoldBufferModal.tsx | 6 +- .../components/modals/ImportTransactions.jsx | 10 +-- .../src/components/modals/LoadBackup.jsx | 14 ++-- .../components/modals/MergeUnusedPayees.jsx | 11 ++- .../src/components/modals/NotesModal.tsx | 6 +- .../modals/ReportBudgetMonthMenuModal.tsx | 23 +++--- .../modals/RolloverBudgetMonthMenuModal.tsx | 23 +++--- .../modals/SelectLinkedAccounts.jsx | 14 ++-- .../components/modals/SimpleFinInitialise.tsx | 8 +- .../components/modals/SingleInputModal.tsx | 80 ++++++++++--------- .../src/components/modals/TransferModal.tsx | 7 +- upcoming-release-notes/2918.md | 6 ++ 29 files changed, 253 insertions(+), 249 deletions(-) create mode 100644 upcoming-release-notes/2918.md diff --git a/packages/desktop-client/src/components/modals/AccountMenuModal.tsx b/packages/desktop-client/src/components/modals/AccountMenuModal.tsx index ecc87e1db..44fbafb33 100644 --- a/packages/desktop-client/src/components/modals/AccountMenuModal.tsx +++ b/packages/desktop-client/src/components/modals/AccountMenuModal.tsx @@ -7,7 +7,7 @@ import { useNotes } from '../../hooks/useNotes'; import { SvgClose, SvgDotsHorizontalTriple, SvgLockOpen } from '../../icons/v1'; import { SvgNotesPaper } from '../../icons/v2'; import { type CSSProperties, styles, theme } from '../../style'; -import { Button } from '../common/Button'; +import { Button } from '../common/Button2'; import { Menu } from '../common/Menu'; import { Modal, ModalTitle } from '../common/Modal'; import { Popover } from '../common/Popover'; @@ -134,7 +134,7 @@ export function AccountMenuModal({ paddingTop: 10, }} > - <Button style={buttonStyle} onClick={_onEditNotes}> + <Button style={buttonStyle} onPress={_onEditNotes}> <SvgNotesPaper width={20} height={20} style={{ paddingRight: 5 }} /> Edit notes </Button> @@ -171,9 +171,9 @@ function AdditionalAccountMenu({ <View> <Button ref={triggerRef} - type="bare" + variant="bare" aria-label="Menu" - onClick={() => { + onPress={() => { setMenuOpen(true); }} > diff --git a/packages/desktop-client/src/components/modals/CategoryGroupMenuModal.tsx b/packages/desktop-client/src/components/modals/CategoryGroupMenuModal.tsx index 776d134d4..4989e6a0c 100644 --- a/packages/desktop-client/src/components/modals/CategoryGroupMenuModal.tsx +++ b/packages/desktop-client/src/components/modals/CategoryGroupMenuModal.tsx @@ -8,7 +8,7 @@ import { useNotes } from '../../hooks/useNotes'; import { SvgDotsHorizontalTriple, SvgAdd, SvgTrash } from '../../icons/v1'; import { SvgNotesPaper, SvgViewHide, SvgViewShow } from '../../icons/v2'; import { type CSSProperties, styles, theme } from '../../style'; -import { Button } from '../common/Button'; +import { Button } from '../common/Button2'; import { Menu } from '../common/Menu'; import { Modal, ModalTitle } from '../common/Modal'; import { Popover } from '../common/Popover'; @@ -140,11 +140,11 @@ export function CategoryGroupMenuModal({ paddingTop: 10, }} > - <Button style={buttonStyle} onClick={_onAddCategory}> + <Button style={buttonStyle} onPress={_onAddCategory}> <SvgAdd width={17} height={17} style={{ paddingRight: 5 }} /> Add category </Button> - <Button style={buttonStyle} onClick={_onEditNotes}> + <Button style={buttonStyle} onPress={_onEditNotes}> <SvgNotesPaper width={20} height={20} style={{ paddingRight: 5 }} /> Edit notes </Button> @@ -172,9 +172,9 @@ function AdditionalCategoryGroupMenu({ group, onDelete, onToggleVisibility }) { {!group.is_income && ( <Button ref={triggerRef} - type="bare" + variant="bare" aria-label="Menu" - onClick={() => { + onPress={() => { setMenuOpen(true); }} > diff --git a/packages/desktop-client/src/components/modals/CategoryMenuModal.tsx b/packages/desktop-client/src/components/modals/CategoryMenuModal.tsx index f56161a45..9451de7cb 100644 --- a/packages/desktop-client/src/components/modals/CategoryMenuModal.tsx +++ b/packages/desktop-client/src/components/modals/CategoryMenuModal.tsx @@ -9,7 +9,7 @@ import { useNotes } from '../../hooks/useNotes'; import { SvgDotsHorizontalTriple, SvgTrash } from '../../icons/v1'; import { SvgNotesPaper, SvgViewHide, SvgViewShow } from '../../icons/v2'; import { type CSSProperties, styles, theme } from '../../style'; -import { Button } from '../common/Button'; +import { Button } from '../common/Button2'; import { Menu } from '../common/Menu'; import { Modal, ModalTitle } from '../common/Modal'; import { Popover } from '../common/Popover'; @@ -131,7 +131,7 @@ export function CategoryMenuModal({ paddingTop: 10, }} > - <Button style={buttonStyle} onClick={_onEditNotes}> + <Button style={buttonStyle} onPress={_onEditNotes}> <SvgNotesPaper width={20} height={20} style={{ paddingRight: 5 }} /> Edit notes </Button> @@ -163,9 +163,9 @@ function AdditionalCategoryMenu({ <View> <Button ref={triggerRef} - type="bare" + variant="bare" aria-label="Menu" - onClick={() => { + onPress={() => { setMenuOpen(true); }} > diff --git a/packages/desktop-client/src/components/modals/CloseAccountModal.tsx b/packages/desktop-client/src/components/modals/CloseAccountModal.tsx index fb9d8411f..93c87019f 100644 --- a/packages/desktop-client/src/components/modals/CloseAccountModal.tsx +++ b/packages/desktop-client/src/components/modals/CloseAccountModal.tsx @@ -1,5 +1,6 @@ // @ts-strict-ignore -import React, { useState } from 'react'; +import React, { type FormEvent, useState } from 'react'; +import { Form } from 'react-aria-components'; import { useDispatch } from 'react-redux'; import { @@ -16,7 +17,7 @@ import { useResponsive } from '../../ResponsiveProvider'; import { type CSSProperties, styles, theme } from '../../style'; import { AccountAutocomplete } from '../autocomplete/AccountAutocomplete'; import { CategoryAutocomplete } from '../autocomplete/CategoryAutocomplete'; -import { Button } from '../common/Button'; +import { Button } from '../common/Button2'; import { FormError } from '../common/FormError'; import { Link } from '../common/Link'; import { Modal } from '../common/Modal'; @@ -86,6 +87,26 @@ export function CloseAccountModal({ } : {}; + const onSubmit = (event: FormEvent<HTMLFormElement>) => { + event.preventDefault(); + + const transferError = balance !== 0 && transferAccountId === ''; + setTransferError(transferError); + + const categoryError = + needsCategory(account, transferAccountId, accounts) && categoryId === ''; + setCategoryError(categoryError); + + if (!transferError && !categoryError) { + setLoading(true); + + dispatch( + closeAccount(account.id, transferAccountId || null, categoryId || null), + ); + modalProps.onClose(); + } + }; + return ( <Modal title="Close Account" @@ -108,32 +129,7 @@ export function CloseAccountModal({ </span> )} </Paragraph> - <form - onSubmit={event => { - event.preventDefault(); - - const transferError = balance !== 0 && transferAccountId === ''; - setTransferError(transferError); - - const categoryError = - needsCategory(account, transferAccountId, accounts) && - categoryId === ''; - setCategoryError(categoryError); - - if (!transferError && !categoryError) { - setLoading(true); - - dispatch( - closeAccount( - account.id, - transferAccountId || null, - categoryId || null, - ), - ); - modalProps.onClose(); - } - }} - > + <Form onSubmit={onSubmit}> {balance !== 0 && ( <View> <Paragraph> @@ -248,12 +244,13 @@ export function CloseAccountModal({ marginRight: 10, height: isNarrowWidth ? styles.mobileMinHeight : undefined, }} - onClick={modalProps.onClose} + onPress={modalProps.onClose} > Cancel </Button> <Button - type="primary" + type="submit" + variant="primary" style={{ height: isNarrowWidth ? styles.mobileMinHeight : undefined, }} @@ -261,7 +258,7 @@ export function CloseAccountModal({ Close Account </Button> </View> - </form> + </Form> </View> )} </Modal> diff --git a/packages/desktop-client/src/components/modals/ConfirmCategoryDelete.tsx b/packages/desktop-client/src/components/modals/ConfirmCategoryDelete.tsx index d12e4306d..a3726e0b9 100644 --- a/packages/desktop-client/src/components/modals/ConfirmCategoryDelete.tsx +++ b/packages/desktop-client/src/components/modals/ConfirmCategoryDelete.tsx @@ -5,7 +5,7 @@ import { useCategories } from '../../hooks/useCategories'; import { theme } from '../../style'; import { CategoryAutocomplete } from '../autocomplete/CategoryAutocomplete'; import { Block } from '../common/Block'; -import { Button } from '../common/Button'; +import { Button } from '../common/Button2'; import { Modal } from '../common/Modal'; import { Text } from '../common/Text'; import { View } from '../common/View'; @@ -118,8 +118,8 @@ export function ConfirmCategoryDelete({ </View> <Button - type="primary" - onClick={() => { + variant="primary" + onPress={() => { if (!transferCategory) { setError('required-transfer'); } else { diff --git a/packages/desktop-client/src/components/modals/ConfirmTransactionDelete.tsx b/packages/desktop-client/src/components/modals/ConfirmTransactionDelete.tsx index 6d465b8e0..f66ea339c 100644 --- a/packages/desktop-client/src/components/modals/ConfirmTransactionDelete.tsx +++ b/packages/desktop-client/src/components/modals/ConfirmTransactionDelete.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { useResponsive } from '../../ResponsiveProvider'; import { styles } from '../../style'; -import { Button } from '../common/Button'; +import { Button } from '../common/Button2'; import { Modal } from '../common/Modal'; import { Paragraph } from '../common/Paragraph'; import { View } from '../common/View'; @@ -39,14 +39,14 @@ export function ConfirmTransactionDelete({ marginRight: 10, ...narrowButtonStyle, }} - onClick={modalProps.onClose} + onPress={modalProps.onClose} > Cancel </Button> <Button - type="primary" + variant="primary" style={narrowButtonStyle} - onClick={() => { + onPress={() => { onConfirm(); modalProps.onClose(); }} diff --git a/packages/desktop-client/src/components/modals/ConfirmTransactionEdit.tsx b/packages/desktop-client/src/components/modals/ConfirmTransactionEdit.tsx index 7ad0ff097..0d88859c5 100644 --- a/packages/desktop-client/src/components/modals/ConfirmTransactionEdit.tsx +++ b/packages/desktop-client/src/components/modals/ConfirmTransactionEdit.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { Block } from '../common/Block'; -import { Button } from '../common/Button'; +import { Button } from '../common/Button2'; import { Modal } from '../common/Modal'; import { View } from '../common/View'; import { type CommonModalProps } from '../Modals'; @@ -75,7 +75,7 @@ export function ConfirmTransactionEdit({ > <Button style={{ marginRight: 10 }} - onClick={() => { + onPress={() => { modalProps.onClose(); onCancel(); }} @@ -83,8 +83,8 @@ export function ConfirmTransactionEdit({ Cancel </Button> <Button - type="primary" - onClick={() => { + variant="primary" + onPress={() => { modalProps.onClose(); onConfirm(); }} diff --git a/packages/desktop-client/src/components/modals/ConfirmUnlinkAccount.tsx b/packages/desktop-client/src/components/modals/ConfirmUnlinkAccount.tsx index 68174829a..88fca3fe7 100644 --- a/packages/desktop-client/src/components/modals/ConfirmUnlinkAccount.tsx +++ b/packages/desktop-client/src/components/modals/ConfirmUnlinkAccount.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { Button } from '../common/Button'; +import { Button } from '../common/Button2'; import { Modal } from '../common/Modal'; import { Paragraph } from '../common/Paragraph'; import { View } from '../common/View'; @@ -36,12 +36,12 @@ export function ConfirmUnlinkAccount({ justifyContent: 'flex-end', }} > - <Button style={{ marginRight: 10 }} onClick={modalProps.onClose}> + <Button style={{ marginRight: 10 }} onPress={modalProps.onClose}> Cancel </Button> <Button - type="primary" - onClick={() => { + variant="primary" + onPress={() => { onUnlink(); modalProps.onClose(); }} diff --git a/packages/desktop-client/src/components/modals/CoverModal.tsx b/packages/desktop-client/src/components/modals/CoverModal.tsx index d268472a9..490f0f4f0 100644 --- a/packages/desktop-client/src/components/modals/CoverModal.tsx +++ b/packages/desktop-client/src/components/modals/CoverModal.tsx @@ -7,7 +7,7 @@ import { useCategories } from '../../hooks/useCategories'; import { useInitialMount } from '../../hooks/useInitialMount'; import { styles } from '../../style'; import { addToBeBudgetedGroup } from '../budget/util'; -import { Button } from '../common/Button'; +import { Button } from '../common/Button2'; import { Modal } from '../common/Modal'; import { View } from '../common/View'; import { FieldLabel, TapField } from '../mobile/MobileForms'; @@ -86,13 +86,13 @@ export function CoverModal({ }} > <Button - type="primary" + variant="primary" style={{ height: styles.mobileMinHeight, marginLeft: styles.mobileEditingPadding, marginRight: styles.mobileEditingPadding, }} - onClick={() => _onSubmit(fromCategoryId)} + onPress={() => _onSubmit(fromCategoryId)} > Transfer </Button> diff --git a/packages/desktop-client/src/components/modals/CreateAccountModal.tsx b/packages/desktop-client/src/components/modals/CreateAccountModal.tsx index d86523128..b9cd815ef 100644 --- a/packages/desktop-client/src/components/modals/CreateAccountModal.tsx +++ b/packages/desktop-client/src/components/modals/CreateAccountModal.tsx @@ -11,7 +11,7 @@ import { useSimpleFinStatus } from '../../hooks/useSimpleFinStatus'; import { type SyncServerStatus } from '../../hooks/useSyncServerStatus'; import { SvgDotsHorizontalTriple } from '../../icons/v1'; import { theme } from '../../style'; -import { Button, ButtonWithLoading } from '../common/Button'; +import { Button, ButtonWithLoading } from '../common/Button2'; import { Link } from '../common/Link'; import { Menu } from '../common/Menu'; import { Modal } from '../common/Modal'; @@ -185,13 +185,13 @@ export function CreateAccountModal({ {upgradingAccountId == null && ( <View style={{ gap: 10 }}> <Button - type="primary" + variant="primary" style={{ padding: '10px 0', fontSize: 15, fontWeight: 600, }} - onClick={onCreateLocalAccount} + onPress={onCreateLocalAccount} > Create local account </Button> @@ -222,14 +222,14 @@ export function CreateAccountModal({ }} > <ButtonWithLoading - disabled={syncServerStatus !== 'online'} + isDisabled={syncServerStatus !== 'online'} style={{ padding: '10px 0', fontSize: 15, fontWeight: 600, flex: 1, }} - onClick={onConnectGoCardless} + onPress={onConnectGoCardless} > {isGoCardlessSetupComplete ? 'Link bank account with GoCardless' @@ -239,9 +239,9 @@ export function CreateAccountModal({ <> <Button ref={triggerRef} - type="bare" - onClick={() => setGoCardlessMenuOpen(true)} - aria-label="Menu" + variant="bare" + onPress={() => setGoCardlessMenuOpen(true)} + aria-label="GoCardless menu" > <SvgDotsHorizontalTriple width={15} @@ -290,15 +290,15 @@ export function CreateAccountModal({ }} > <ButtonWithLoading - disabled={syncServerStatus !== 'online'} - loading={loadingSimpleFinAccounts} + isDisabled={syncServerStatus !== 'online'} + isLoading={loadingSimpleFinAccounts} style={{ padding: '10px 0', fontSize: 15, fontWeight: 600, flex: 1, }} - onClick={onConnectSimpleFin} + onPress={onConnectSimpleFin} > {isSimpleFinSetupComplete ? 'Link bank account with SimpleFIN' @@ -308,9 +308,9 @@ export function CreateAccountModal({ <> <Button ref={triggerRef} - type="bare" - onClick={() => setSimplefinMenuOpen(true)} - aria-label="Menu" + variant="bare" + onPress={() => setSimplefinMenuOpen(true)} + aria-label="SimpleFIN menu" > <SvgDotsHorizontalTriple width={15} @@ -353,7 +353,7 @@ export function CreateAccountModal({ ) : ( <> <Button - disabled + isDisabled style={{ padding: '10px 0', fontSize: 15, diff --git a/packages/desktop-client/src/components/modals/CreateEncryptionKeyModal.tsx b/packages/desktop-client/src/components/modals/CreateEncryptionKeyModal.tsx index f8d971b4e..1c39b5aa9 100644 --- a/packages/desktop-client/src/components/modals/CreateEncryptionKeyModal.tsx +++ b/packages/desktop-client/src/components/modals/CreateEncryptionKeyModal.tsx @@ -10,7 +10,7 @@ import { getCreateKeyError } from 'loot-core/src/shared/errors'; import { useResponsive } from '../../ResponsiveProvider'; import { styles, theme } from '../../style'; -import { ButtonWithLoading } from '../common/Button'; +import { ButtonWithLoading } from '../common/Button2'; import { InitialFocus } from '../common/InitialFocus'; import { Input } from '../common/Input'; import { Link } from '../common/Link'; @@ -187,11 +187,11 @@ export function CreateEncryptionKeyModal({ <ModalButtons style={{ marginTop: 20 }}> <ButtonWithLoading + variant="primary" style={{ height: isNarrowWidth ? styles.mobileMinHeight : undefined, }} - loading={loading} - type="primary" + isLoading={loading} > Enable </ButtonWithLoading> diff --git a/packages/desktop-client/src/components/modals/CreateLocalAccountModal.tsx b/packages/desktop-client/src/components/modals/CreateLocalAccountModal.tsx index 2783acf2c..0e3dcc079 100644 --- a/packages/desktop-client/src/components/modals/CreateLocalAccountModal.tsx +++ b/packages/desktop-client/src/components/modals/CreateLocalAccountModal.tsx @@ -1,12 +1,13 @@ // @ts-strict-ignore -import React, { useState } from 'react'; +import React, { type FormEvent, useState } from 'react'; +import { Form } from 'react-aria-components'; import { toRelaxedNumber } from 'loot-core/src/shared/util'; import { type BoundActions } from '../../hooks/useActions'; import { useNavigate } from '../../hooks/useNavigate'; import { theme } from '../../style'; -import { Button } from '../common/Button'; +import { Button } from '../common/Button2'; import { FormError } from '../common/FormError'; import { InitialFocus } from '../common/InitialFocus'; import { InlineField } from '../common/InlineField'; @@ -37,6 +38,25 @@ export function CreateLocalAccountModal({ const validateBalance = balance => !isNaN(parseFloat(balance)); + const onSubmit = async (event: FormEvent<HTMLFormElement>) => { + event.preventDefault(); + + const nameError = !name; + setNameError(nameError); + + const balanceError = !validateBalance(balance); + setBalanceError(balanceError); + + if (!nameError && !balanceError) { + actions.closeModal(); + const id = await actions.createAccount( + name, + toRelaxedNumber(balance), + offbudget, + ); + navigate('/accounts/' + id); + } + }; return ( <Modal title={<ModalTitle title="Create Local Account" shrinkOnOverflow />} @@ -44,27 +64,7 @@ export function CreateLocalAccountModal({ > {() => ( <View> - <form - onSubmit={async event => { - event.preventDefault(); - - const nameError = !name; - setNameError(nameError); - - const balanceError = !validateBalance(balance); - setBalanceError(balanceError); - - if (!nameError && !balanceError) { - actions.closeModal(); - const id = await actions.createAccount( - name, - toRelaxedNumber(balance), - offbudget, - ); - navigate('/accounts/' + id); - } - }} - > + <Form onSubmit={onSubmit}> <InlineField label="Name" width="100%"> <InitialFocus> <Input @@ -163,12 +163,16 @@ export function CreateLocalAccountModal({ )} <ModalButtons> - <Button onClick={() => modalProps.onBack()}>Back</Button> - <Button type="primary" style={{ marginLeft: 10 }}> + <Button onPress={() => modalProps.onBack()}>Back</Button> + <Button + type="submit" + variant="primary" + style={{ marginLeft: 10 }} + > Create </Button> </ModalButtons> - </form> + </Form> </View> )} </Modal> diff --git a/packages/desktop-client/src/components/modals/EditField.jsx b/packages/desktop-client/src/components/modals/EditField.jsx index 295d77659..3ffc5168b 100644 --- a/packages/desktop-client/src/components/modals/EditField.jsx +++ b/packages/desktop-client/src/components/modals/EditField.jsx @@ -8,7 +8,7 @@ import { amountToInteger } from 'loot-core/src/shared/util'; import { useDateFormat } from '../../hooks/useDateFormat'; import { useResponsive } from '../../ResponsiveProvider'; import { theme } from '../../style'; -import { Button } from '../common/Button'; +import { Button } from '../common/Button2'; import { Input } from '../common/Input'; import { Modal } from '../common/Modal'; import { View } from '../common/View'; @@ -116,7 +116,7 @@ export function EditField({ modalProps, name, onSubmit, onClose }) { }, }), }} - onClick={() => { + onPress={() => { onChangeMode('prepend'); document.getElementById('noteInput').focus(); }} @@ -148,7 +148,7 @@ export function EditField({ modalProps, name, onSubmit, onClose }) { }, }), }} - onClick={() => { + onPress={() => { onChangeMode('replace'); document.getElementById('noteInput').focus(); }} @@ -180,7 +180,7 @@ export function EditField({ modalProps, name, onSubmit, onClose }) { }, }), }} - onClick={() => { + onPress={() => { onChangeMode('append'); document.getElementById('noteInput').focus(); }} diff --git a/packages/desktop-client/src/components/modals/EditRule.jsx b/packages/desktop-client/src/components/modals/EditRule.jsx index 8c14b40c1..b54ec5d65 100644 --- a/packages/desktop-client/src/components/modals/EditRule.jsx +++ b/packages/desktop-client/src/components/modals/EditRule.jsx @@ -40,7 +40,7 @@ import { useSelected, SelectedProvider } from '../../hooks/useSelected'; import { SvgDelete, SvgAdd, SvgSubtract } from '../../icons/v0'; import { SvgInformationOutline } from '../../icons/v1'; import { styles, theme } from '../../style'; -import { Button } from '../common/Button'; +import { Button } from '../common/Button2'; import { Menu } from '../common/Menu'; import { Modal } from '../common/Modal'; import { Select } from '../common/Select'; @@ -157,8 +157,8 @@ function EditorButtons({ onAdd, onDelete }) { <> {onDelete && ( <Button - type="bare" - onClick={onDelete} + variant="bare" + onPress={onDelete} style={{ padding: 7 }} aria-label="Delete entry" > @@ -167,8 +167,8 @@ function EditorButtons({ onAdd, onDelete }) { )} {onAdd && ( <Button - type="bare" - onClick={onAdd} + variant="bare" + onPress={onAdd} style={{ padding: 7 }} aria-label="Add entry" > @@ -462,7 +462,7 @@ function StageInfo() { function StageButton({ selected, children, style, onSelect }) { return ( <Button - type="bare" + variant="bare" style={{ fontSize: 'inherit', ...(selected && { @@ -471,7 +471,7 @@ function StageButton({ selected, children, style, onSelect }) { }), ...style, }} - onClick={onSelect} + onPress={onSelect} > {children} </Button> @@ -611,7 +611,7 @@ function ConditionsList({ } return conditions.length === 0 ? ( - <Button style={{ alignSelf: 'flex-start' }} onClick={addInitialCondition}> + <Button style={{ alignSelf: 'flex-start' }} onPress={addInitialCondition}> Add condition </Button> ) : ( @@ -996,7 +996,7 @@ export function EditRule({ modalProps, defaultRule, onSave: originalOnSave }) { {actionSplits.length === 0 && ( <Button style={{ alignSelf: 'flex-start' }} - onClick={addInitialAction} + onPress={addInitialAction} > Add action </Button> @@ -1034,8 +1034,8 @@ export function EditRule({ modalProps, defaultRule, onSave: originalOnSave }) { </Text> {splitIndex && ( <Button - type="bare" - onClick={() => onRemoveSplit(splitIndex)} + variant="bare" + onPress={() => onRemoveSplit(splitIndex)} style={{ width: 20, height: 20, @@ -1078,7 +1078,7 @@ export function EditRule({ modalProps, defaultRule, onSave: originalOnSave }) { {actions.length === 0 && ( <Button style={{ alignSelf: 'flex-start', marginTop: 5 }} - onClick={() => + onPress={() => addActionToSplitAfterIndex(splitIndex, -1) } > @@ -1091,7 +1091,7 @@ export function EditRule({ modalProps, defaultRule, onSave: originalOnSave }) { {showSplitButton && ( <Button style={{ alignSelf: 'flex-start', marginTop: 15 }} - onClick={() => { + onPress={() => { addActionToSplitAfterIndex(actionSplits.length, -1); }} data-testid="add-split-transactions" @@ -1120,8 +1120,8 @@ export function EditRule({ modalProps, defaultRule, onSave: originalOnSave }) { <View style={{ flex: 1 }} /> <Button - disabled={selectedInst.items.size === 0} - onClick={onApply} + isDisabled={selectedInst.items.size === 0} + onPress={onApply} > Apply actions ({selectedInst.items.size}) </Button> @@ -1144,8 +1144,8 @@ export function EditRule({ modalProps, defaultRule, onSave: originalOnSave }) { justify="flex-end" style={{ marginTop: 20 }} > - <Button onClick={() => modalProps.onClose()}>Cancel</Button> - <Button type="primary" onClick={() => onSave()}> + <Button onPress={() => modalProps.onClose()}>Cancel</Button> + <Button variant="primary" onPress={() => onSave()}> Save </Button> </Stack> diff --git a/packages/desktop-client/src/components/modals/FixEncryptionKeyModal.tsx b/packages/desktop-client/src/components/modals/FixEncryptionKeyModal.tsx index 199b539f0..4efbe26ed 100644 --- a/packages/desktop-client/src/components/modals/FixEncryptionKeyModal.tsx +++ b/packages/desktop-client/src/components/modals/FixEncryptionKeyModal.tsx @@ -1,5 +1,6 @@ // @ts-strict-ignore import React, { useState } from 'react'; +import { Form } from 'react-aria-components'; import { type FinanceModals } from 'loot-core/src/client/state-types/modals'; import { send } from 'loot-core/src/platform/client/fetch'; @@ -7,7 +8,7 @@ import { getTestKeyError } from 'loot-core/src/shared/errors'; import { useResponsive } from '../../ResponsiveProvider'; import { styles, theme } from '../../style'; -import { Button, ButtonWithLoading } from '../common/Button'; +import { Button, ButtonWithLoading } from '../common/Button2'; import { InitialFocus } from '../common/InitialFocus'; import { Input } from '../common/Input'; import { Link } from '../common/Link'; @@ -95,7 +96,7 @@ export function FixEncryptionKeyModal({ </Paragraph> )} </View> - <form + <Form onSubmit={e => { e.preventDefault(); onUpdateKey(); @@ -144,27 +145,27 @@ export function FixEncryptionKeyModal({ <ModalButtons style={{ marginTop: 20 }}> <Button + variant="normal" style={{ height: isNarrowWidth ? styles.mobileMinHeight : undefined, marginRight: 10, }} - onClick={() => modalProps.onBack()} - type="normal" + onPress={() => modalProps.onBack()} > Back </Button> <ButtonWithLoading - type="primary" + type="submit" + variant="primary" style={{ height: isNarrowWidth ? styles.mobileMinHeight : undefined, }} - loading={loading} - onClick={onUpdateKey} + isLoading={loading} > {hasExistingKey ? 'Update key' : 'Create key'} </ButtonWithLoading> </ModalButtons> - </form> + </Form> </Modal> ); } diff --git a/packages/desktop-client/src/components/modals/GoCardlessExternalMsg.tsx b/packages/desktop-client/src/components/modals/GoCardlessExternalMsg.tsx index 1a0ff3d57..9cb6e106b 100644 --- a/packages/desktop-client/src/components/modals/GoCardlessExternalMsg.tsx +++ b/packages/desktop-client/src/components/modals/GoCardlessExternalMsg.tsx @@ -14,7 +14,7 @@ import { AnimatedLoading } from '../../icons/AnimatedLoading'; import { theme } from '../../style'; import { Error, Warning } from '../alerts'; import { Autocomplete } from '../autocomplete/Autocomplete'; -import { Button } from '../common/Button'; +import { Button } from '../common/Button2'; import { Link } from '../common/Link'; import { Modal } from '../common/Modal'; import { Paragraph } from '../common/Paragraph'; @@ -213,15 +213,15 @@ export function GoCardlessExternalMsg({ <View style={{ flexDirection: 'row', gap: 10, alignItems: 'center' }}> <Button - type="primary" + variant="primary" style={{ padding: '10px 0', fontSize: 15, fontWeight: 600, flexGrow: 1, }} - onClick={onJump} - disabled={!institutionId || !country} + onPress={onJump} + isDisabled={!institutionId || !country} > Link bank in browser → </Button> @@ -271,14 +271,14 @@ export function GoCardlessExternalMsg({ </View> ) : success ? ( <Button - type="primary" + variant="primary" style={{ padding: '10px 0', fontSize: 15, fontWeight: 600, marginTop: 10, }} - onClick={onContinue} + onPress={onContinue} > Success! Click to continue → </Button> @@ -289,7 +289,7 @@ export function GoCardlessExternalMsg({ <Paragraph style={{ color: theme.errorText }}> GoCardless integration has not yet been configured. </Paragraph> - <Button type="primary" onClick={onGoCardlessInit}> + <Button variant="primary" onPress={onGoCardlessInit}> Configure GoCardless integration </Button> </> diff --git a/packages/desktop-client/src/components/modals/GoCardlessInitialise.tsx b/packages/desktop-client/src/components/modals/GoCardlessInitialise.tsx index 8857962e0..021d488a3 100644 --- a/packages/desktop-client/src/components/modals/GoCardlessInitialise.tsx +++ b/packages/desktop-client/src/components/modals/GoCardlessInitialise.tsx @@ -4,7 +4,7 @@ import React, { useState } from 'react'; import { send } from 'loot-core/src/platform/client/fetch'; import { Error } from '../alerts'; -import { ButtonWithLoading } from '../common/Button'; +import { ButtonWithLoading } from '../common/Button2'; import { Input } from '../common/Input'; import { Link } from '../common/Link'; import { Modal, ModalButtons } from '../common/Modal'; @@ -103,9 +103,9 @@ export const GoCardlessInitialise = ({ <ModalButtons> <ButtonWithLoading - type="primary" - loading={isLoading} - onClick={onSubmit} + variant="primary" + isLoading={isLoading} + onPress={onSubmit} > Save and continue </ButtonWithLoading> diff --git a/packages/desktop-client/src/components/modals/HoldBufferModal.tsx b/packages/desktop-client/src/components/modals/HoldBufferModal.tsx index 976f1948e..292f92c8a 100644 --- a/packages/desktop-client/src/components/modals/HoldBufferModal.tsx +++ b/packages/desktop-client/src/components/modals/HoldBufferModal.tsx @@ -3,7 +3,7 @@ import React, { useState } from 'react'; import { rolloverBudget } from 'loot-core/client/queries'; import { styles } from '../../style'; -import { Button } from '../common/Button'; +import { Button } from '../common/Button2'; import { InitialFocus } from '../common/InitialFocus'; import { Modal } from '../common/Modal'; import { View } from '../common/View'; @@ -66,13 +66,13 @@ export function HoldBufferModal({ }} > <Button - type="primary" + variant="primary" style={{ height: styles.mobileMinHeight, marginLeft: styles.mobileEditingPadding, marginRight: styles.mobileEditingPadding, }} - onClick={() => _onSubmit(amount)} + onPress={() => _onSubmit(amount)} > Hold </Button> diff --git a/packages/desktop-client/src/components/modals/ImportTransactions.jsx b/packages/desktop-client/src/components/modals/ImportTransactions.jsx index b1675e77e..1c41776d7 100644 --- a/packages/desktop-client/src/components/modals/ImportTransactions.jsx +++ b/packages/desktop-client/src/components/modals/ImportTransactions.jsx @@ -1463,7 +1463,7 @@ export function ImportTransactions({ modalProps, options }) { <strong>Error:</strong> {error.message} </Text> {error.parsed && ( - <Button onClick={() => onNewFile()}>Select new file...</Button> + <Button onPress={() => onNewFile()}>Select new file...</Button> )} </View> )} @@ -1671,13 +1671,13 @@ export function ImportTransactions({ modalProps, options }) { }} > <ButtonWithLoading - type="primary" - disabled={ + variant="primary" + isDisabled={ transactions?.filter(trans => !trans.isMatchedTransaction) .length === 0 } - loading={loadingState === 'importing'} - onClick={onImport} + isLoading={loadingState === 'importing'} + onPress={onImport} > Import{' '} {transactions?.filter(trans => !trans.isMatchedTransaction).length}{' '} diff --git a/packages/desktop-client/src/components/modals/LoadBackup.jsx b/packages/desktop-client/src/components/modals/LoadBackup.jsx index 741b41d7c..9ed813034 100644 --- a/packages/desktop-client/src/components/modals/LoadBackup.jsx +++ b/packages/desktop-client/src/components/modals/LoadBackup.jsx @@ -5,7 +5,7 @@ import { send, listen, unlisten } from 'loot-core/src/platform/client/fetch'; import { useLocalPref } from '../../hooks/useLocalPref'; import { theme } from '../../style'; import { Block } from '../common/Block'; -import { Button } from '../common/Button'; +import { Button } from '../common/Button2'; import { Modal } from '../common/Modal'; import { Text } from '../common/Text'; import { View } from '../common/View'; @@ -95,8 +95,8 @@ export function LoadBackup({ version below. </Block> <Button - type="primary" - onClick={() => + variant="primary" + onPress={() => actions.loadBackup(budgetIdToLoad, latestBackup.id) } > @@ -114,11 +114,11 @@ export function LoadBackup({ </Text> </Block> <Button - type="primary" - disabled={backupDisabled} - onClick={() => actions.makeBackup()} + variant="primary" + isDisabled={backupDisabled} + onPress={() => actions.makeBackup()} > - Backup Now + Backup now </Button> </View> )} diff --git a/packages/desktop-client/src/components/modals/MergeUnusedPayees.jsx b/packages/desktop-client/src/components/modals/MergeUnusedPayees.jsx index 78d0efc17..fc1535a89 100644 --- a/packages/desktop-client/src/components/modals/MergeUnusedPayees.jsx +++ b/packages/desktop-client/src/components/modals/MergeUnusedPayees.jsx @@ -7,7 +7,7 @@ import { send } from 'loot-core/src/platform/client/fetch'; import { usePayees } from '../../hooks/usePayees'; import { theme } from '../../style'; import { Information } from '../alerts'; -import { Button } from '../common/Button'; +import { Button } from '../common/Button2'; import { Modal, ModalButtons } from '../common/Modal'; import { Paragraph } from '../common/Paragraph'; import { Text } from '../common/Text'; @@ -157,24 +157,23 @@ export function MergeUnusedPayees({ modalProps, payeeIds, targetPayeeId }) { <ModalButtons style={{ marginTop: 20 }} focusButton> <Button - type="primary" - isSubmit={false} + variant="primary" style={{ marginRight: 10 }} - onClick={onMerge} + onPress={onMerge} > Merge </Button> {!isEditingRule && ( <Button style={{ marginRight: 10 }} - onClick={onMergeAndCreateRule} + onPress={onMergeAndCreateRule} > Merge and edit rule </Button> )} <Button style={{ marginRight: 10 }} - onClick={() => modalProps.onBack()} + onPress={() => modalProps.onBack()} > Do nothing </Button> diff --git a/packages/desktop-client/src/components/modals/NotesModal.tsx b/packages/desktop-client/src/components/modals/NotesModal.tsx index 54f4b819e..04bd35823 100644 --- a/packages/desktop-client/src/components/modals/NotesModal.tsx +++ b/packages/desktop-client/src/components/modals/NotesModal.tsx @@ -3,7 +3,7 @@ import React, { useEffect, useState } from 'react'; import { useNotes } from '../../hooks/useNotes'; import { SvgCheck } from '../../icons/v2'; -import { Button } from '../common/Button'; +import { Button } from '../common/Button2'; import { Modal } from '../common/Modal'; import { View } from '../common/View'; import { type CommonModalProps } from '../Modals'; @@ -72,13 +72,13 @@ export function NotesModal({ modalProps, id, name, onSave }: NotesModalProps) { }} > <Button - type="primary" + variant="primary" style={{ fontSize: 17, fontWeight: 400, width: '100%', }} - onClick={_onSave} + onPress={_onSave} > <SvgCheck width={17} height={17} style={{ paddingRight: 5 }} /> Save notes diff --git a/packages/desktop-client/src/components/modals/ReportBudgetMonthMenuModal.tsx b/packages/desktop-client/src/components/modals/ReportBudgetMonthMenuModal.tsx index 757e1fdec..72eee1de2 100644 --- a/packages/desktop-client/src/components/modals/ReportBudgetMonthMenuModal.tsx +++ b/packages/desktop-client/src/components/modals/ReportBudgetMonthMenuModal.tsx @@ -8,7 +8,7 @@ import { SvgCheveronDown, SvgCheveronUp } from '../../icons/v1'; import { SvgNotesPaper } from '../../icons/v2'; import { type CSSProperties, styles, theme } from '../../style'; import { BudgetMonthMenu } from '../budget/report/budgetsummary/BudgetMonthMenu'; -import { Button } from '../common/Button'; +import { Button } from '../common/Button2'; import { Modal, ModalTitle } from '../common/Modal'; import { View } from '../common/View'; import { type CommonModalProps } from '../Modals'; @@ -106,7 +106,7 @@ export function ReportBudgetMonthMenuModal({ alignContent: 'space-between', }} > - <Button style={buttonStyle} onClick={_onEditNotes}> + <Button style={buttonStyle} onPress={_onEditNotes}> <SvgNotesPaper width={20} height={20} @@ -117,17 +117,14 @@ export function ReportBudgetMonthMenuModal({ </View> <View> <Button - type="bare" - style={buttonStyle} - activeStyle={{ - backgroundColor: 'transparent', - color: buttonStyle.color, - }} - hoveredStyle={{ - backgroundColor: 'transparent', - color: buttonStyle.color, - }} - onClick={onShowMore} + variant="bare" + style={({ isPressed, isHovered }) => ({ + ...buttonStyle, + ...(isPressed || isHovered + ? { backgroundColor: 'transparent', color: buttonStyle.color } + : {}), + })} + onPress={onShowMore} > {!showMore ? ( <SvgCheveronUp diff --git a/packages/desktop-client/src/components/modals/RolloverBudgetMonthMenuModal.tsx b/packages/desktop-client/src/components/modals/RolloverBudgetMonthMenuModal.tsx index 45a1824b7..707024225 100644 --- a/packages/desktop-client/src/components/modals/RolloverBudgetMonthMenuModal.tsx +++ b/packages/desktop-client/src/components/modals/RolloverBudgetMonthMenuModal.tsx @@ -8,7 +8,7 @@ import { SvgCheveronDown, SvgCheveronUp } from '../../icons/v1'; import { SvgNotesPaper } from '../../icons/v2'; import { type CSSProperties, styles, theme } from '../../style'; import { BudgetMonthMenu } from '../budget/rollover/budgetsummary/BudgetMonthMenu'; -import { Button } from '../common/Button'; +import { Button } from '../common/Button2'; import { Modal, ModalTitle } from '../common/Modal'; import { View } from '../common/View'; import { type CommonModalProps } from '../Modals'; @@ -106,7 +106,7 @@ export function RolloverBudgetMonthMenuModal({ alignContent: 'space-between', }} > - <Button style={buttonStyle} onClick={_onEditNotes}> + <Button style={buttonStyle} onPress={_onEditNotes}> <SvgNotesPaper width={20} height={20} @@ -117,17 +117,14 @@ export function RolloverBudgetMonthMenuModal({ </View> <View> <Button - type="bare" - style={buttonStyle} - activeStyle={{ - backgroundColor: 'transparent', - color: buttonStyle.color, - }} - hoveredStyle={{ - backgroundColor: 'transparent', - color: buttonStyle.color, - }} - onClick={onShowMore} + variant="bare" + style={({ isPressed, isHovered }) => ({ + ...buttonStyle, + ...(isPressed || isHovered + ? { backgroundColor: 'transparent', color: buttonStyle.color } + : {}), + })} + onPress={onShowMore} > {!showMore ? ( <SvgCheveronUp diff --git a/packages/desktop-client/src/components/modals/SelectLinkedAccounts.jsx b/packages/desktop-client/src/components/modals/SelectLinkedAccounts.jsx index d722c23dd..4dcc8696c 100644 --- a/packages/desktop-client/src/components/modals/SelectLinkedAccounts.jsx +++ b/packages/desktop-client/src/components/modals/SelectLinkedAccounts.jsx @@ -3,7 +3,7 @@ import React, { useState } from 'react'; import { useAccounts } from '../../hooks/useAccounts'; import { theme } from '../../style'; import { Autocomplete } from '../autocomplete/Autocomplete'; -import { Button } from '../common/Button'; +import { Button } from '../common/Button2'; import { Modal } from '../common/Modal'; import { Text } from '../common/Text'; import { View } from '../common/View'; @@ -160,9 +160,9 @@ export function SelectLinkedAccounts({ }} > <Button - type="primary" - onClick={onNext} - disabled={!Object.keys(chosenAccounts).length} + variant="primary" + onPress={onNext} + isDisabled={!Object.keys(chosenAccounts).length} > Link accounts </Button> @@ -220,7 +220,7 @@ function TableRow({ <Field width="20%"> {chosenAccount ? ( <Button - onClick={() => { + onPress={() => { onSetLinkedAccount(externalAccount, null); }} style={{ float: 'right' }} @@ -229,8 +229,8 @@ function TableRow({ </Button> ) : ( <Button - type="primary" - onClick={() => { + variant="primary" + onPress={() => { setFocusedField('account'); }} style={{ float: 'right' }} diff --git a/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx b/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx index 6eeff3281..37d0a2d78 100644 --- a/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx +++ b/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx @@ -4,7 +4,7 @@ import React, { useState } from 'react'; import { send } from 'loot-core/src/platform/client/fetch'; import { Error } from '../alerts'; -import { ButtonWithLoading } from '../common/Button'; +import { ButtonWithLoading } from '../common/Button2'; import { Input } from '../common/Input'; import { Link } from '../common/Link'; import { Modal, ModalButtons } from '../common/Modal'; @@ -79,9 +79,9 @@ export const SimpleFinInitialise = ({ <ModalButtons> <ButtonWithLoading - type="primary" - loading={isLoading} - onClick={onSubmit} + variant="primary" + isLoading={isLoading} + onPress={onSubmit} > Save and continue </ButtonWithLoading> diff --git a/packages/desktop-client/src/components/modals/SingleInputModal.tsx b/packages/desktop-client/src/components/modals/SingleInputModal.tsx index 4bda6b5d3..8ba91fcb7 100644 --- a/packages/desktop-client/src/components/modals/SingleInputModal.tsx +++ b/packages/desktop-client/src/components/modals/SingleInputModal.tsx @@ -1,8 +1,9 @@ // @ts-strict-ignore -import React, { type ComponentProps, useState } from 'react'; +import React, { type ComponentProps, useState, type FormEvent } from 'react'; +import { Form } from 'react-aria-components'; import { styles } from '../../style'; -import { Button } from '../common/Button'; +import { Button } from '../common/Button2'; import { FormError } from '../common/FormError'; import { InitialFocus } from '../common/InitialFocus'; import { Modal } from '../common/Modal'; @@ -30,7 +31,9 @@ export function SingleInputModal({ const [value, setValue] = useState(''); const [errorMessage, setErrorMessage] = useState(null); - const _onSubmit = value => { + const _onSubmit = (e: FormEvent<HTMLFormElement>) => { + e.preventDefault(); + const error = onValidate?.(value); if (error) { setErrorMessage(error); @@ -43,46 +46,47 @@ export function SingleInputModal({ return ( <Modal title={title} {...modalProps}> - <View> - <InitialFocus> - <InputField - placeholder={inputPlaceholder} - defaultValue={value} - onUpdate={setValue} - onEnter={e => _onSubmit(e.currentTarget.value)} - /> - </InitialFocus> - {errorMessage && ( - <FormError + <Form onSubmit={_onSubmit}> + <View> + <InitialFocus> + <InputField + placeholder={inputPlaceholder} + defaultValue={value} + onChangeValue={setValue} + /> + </InitialFocus> + {errorMessage && ( + <FormError + style={{ + paddingTop: 5, + marginLeft: styles.mobileEditingPadding, + marginRight: styles.mobileEditingPadding, + }} + > + * {errorMessage} + </FormError> + )} + </View> + <View + style={{ + justifyContent: 'center', + alignItems: 'center', + paddingTop: 10, + }} + > + <Button + type="submit" + variant="primary" style={{ - paddingTop: 5, + height: styles.mobileMinHeight, marginLeft: styles.mobileEditingPadding, marginRight: styles.mobileEditingPadding, }} > - * {errorMessage} - </FormError> - )} - </View> - <View - style={{ - justifyContent: 'center', - alignItems: 'center', - paddingTop: 10, - }} - > - <Button - type="primary" - style={{ - height: styles.mobileMinHeight, - marginLeft: styles.mobileEditingPadding, - marginRight: styles.mobileEditingPadding, - }} - onClick={() => _onSubmit(value)} - > - {buttonText} - </Button> - </View> + {buttonText} + </Button> + </View> + </Form> </Modal> ); } diff --git a/packages/desktop-client/src/components/modals/TransferModal.tsx b/packages/desktop-client/src/components/modals/TransferModal.tsx index 5af37bb8b..0361c0685 100644 --- a/packages/desktop-client/src/components/modals/TransferModal.tsx +++ b/packages/desktop-client/src/components/modals/TransferModal.tsx @@ -6,7 +6,7 @@ import { pushModal } from 'loot-core/client/actions'; import { useCategories } from '../../hooks/useCategories'; import { styles } from '../../style'; import { addToBeBudgetedGroup } from '../budget/util'; -import { Button } from '../common/Button'; +import { Button } from '../common/Button2'; import { InitialFocus } from '../common/InitialFocus'; import { Modal } from '../common/Modal'; import { View } from '../common/View'; @@ -109,14 +109,13 @@ export function TransferModal({ }} > <Button - type="primary" - tabIndex={0} + variant="primary" style={{ height: styles.mobileMinHeight, marginLeft: styles.mobileEditingPadding, marginRight: styles.mobileEditingPadding, }} - onClick={() => _onSubmit(amount, toCategoryId)} + onPress={() => _onSubmit(amount, toCategoryId)} > Transfer </Button> diff --git a/upcoming-release-notes/2918.md b/upcoming-release-notes/2918.md new file mode 100644 index 000000000..a5c8daab2 --- /dev/null +++ b/upcoming-release-notes/2918.md @@ -0,0 +1,6 @@ +--- +category: Maintenance +authors: [joel-jeremy] +--- + +Use new react-aria-components based Button on modals. -- GitLab