From 89241623f31c075502841ef85bd1c2b2fcd86ef7 Mon Sep 17 00:00:00 2001 From: Joel Jeremy Marquez <joeljeremy.marquez@gmail.com> Date: Wed, 17 Jul 2024 12:20:12 -0700 Subject: [PATCH] React Aria Button on Management App (#2916) * React Aria Button on management app * Release notes * Update release notes * Fix typecheck error * Remove aria labels * Apply suggestions from code review Co-authored-by: Matiss Janis Aboltins <matiss@mja.lv> * Remove aria-labels * Remove aria-label --------- Co-authored-by: Matiss Janis Aboltins <matiss@mja.lv> --- .../src/components/manager/BudgetList.tsx | 25 ++++++------ .../src/components/manager/ConfigServer.tsx | 38 +++++++++---------- .../src/components/manager/DeleteFile.tsx | 14 +++---- .../src/components/manager/Import.tsx | 8 ++-- .../src/components/manager/ImportActual.tsx | 8 ++-- .../src/components/manager/ImportYNAB4.tsx | 8 ++-- .../src/components/manager/ImportYNAB5.tsx | 8 ++-- .../src/components/manager/WelcomeScreen.tsx | 8 ++-- .../manager/subscribe/Bootstrap.tsx | 6 +-- .../manager/subscribe/ChangePassword.tsx | 6 +-- .../manager/subscribe/ConfirmPasswordForm.tsx | 26 ++++++------- .../components/manager/subscribe/Error.tsx | 4 +- .../components/manager/subscribe/Login.tsx | 28 ++++++-------- upcoming-release-notes/2916.md | 6 +++ 14 files changed, 93 insertions(+), 100 deletions(-) create mode 100644 upcoming-release-notes/2916.md diff --git a/packages/desktop-client/src/components/manager/BudgetList.tsx b/packages/desktop-client/src/components/manager/BudgetList.tsx index 9e30b3a1b..2686697f0 100644 --- a/packages/desktop-client/src/components/manager/BudgetList.tsx +++ b/packages/desktop-client/src/components/manager/BudgetList.tsx @@ -33,7 +33,7 @@ import { SvgCloudUnknown, SvgKey, SvgRefreshArrow } from '../../icons/v2'; import { useResponsive } from '../../ResponsiveProvider'; import { styles, theme } from '../../style'; import { tokens } from '../../tokens'; -import { Button } from '../common/Button'; +import { Button } from '../common/Button2'; import { Menu } from '../common/Menu'; import { Popover } from '../common/Popover'; import { Text } from '../common/Text'; @@ -104,10 +104,9 @@ function FileMenuButton({ onDelete }: { onDelete: () => void }) { <View> <Button ref={triggerRef} - type="bare" + variant="bare" aria-label="Menu" - onClick={e => { - e.stopPropagation(); + onPress={() => { setMenuOpen(true); }} > @@ -315,10 +314,10 @@ function RefreshButton({ return ( <Button - type="bare" + variant="bare" aria-label="Refresh" style={{ padding: 10, ...style }} - onClick={_onRefresh} + onPress={_onRefresh} > <Icon style={{ width: 18, height: 18 }} /> </Button> @@ -444,14 +443,13 @@ export function BudgetList({ showHeader = true, quickSwitchMode = false }) { }} > <Button - type="bare" + variant="bare" style={{ ...narrowButtonStyle, marginLeft: 10, color: theme.pageTextLight, }} - onClick={e => { - e.preventDefault(); + onPress={() => { dispatch(pushModal('import')); }} > @@ -459,8 +457,8 @@ export function BudgetList({ showHeader = true, quickSwitchMode = false }) { </Button> <Button - type="primary" - onClick={() => onCreate()} + variant="primary" + onPress={() => onCreate()} style={{ ...narrowButtonStyle, marginLeft: 10, @@ -471,9 +469,8 @@ export function BudgetList({ showHeader = true, quickSwitchMode = false }) { {isNonProductionEnvironment() && ( <Button - type="primary" - isSubmit={false} - onClick={() => onCreate({ testMode: true })} + variant="primary" + onPress={() => onCreate({ testMode: true })} style={{ ...narrowButtonStyle, marginLeft: 10, diff --git a/packages/desktop-client/src/components/manager/ConfigServer.tsx b/packages/desktop-client/src/components/manager/ConfigServer.tsx index 742d477b8..5d4864dbb 100644 --- a/packages/desktop-client/src/components/manager/ConfigServer.tsx +++ b/packages/desktop-client/src/components/manager/ConfigServer.tsx @@ -10,7 +10,7 @@ import { useActions } from '../../hooks/useActions'; import { useNavigate } from '../../hooks/useNavigate'; import { useSetThemeColor } from '../../hooks/useSetThemeColor'; import { theme } from '../../style'; -import { Button, ButtonWithLoading } from '../common/Button'; +import { Button, ButtonWithLoading } from '../common/Button2'; import { BigInput } from '../common/Input'; import { Text } from '../common/Text'; import { View } from '../common/View'; @@ -127,37 +127,33 @@ export function ConfigServer() { </Text> )} - <form - style={{ display: 'flex', flexDirection: 'row', marginTop: 30 }} - onSubmit={e => { - e.preventDefault(); - onSubmit(); - }} - > + <View style={{ display: 'flex', flexDirection: 'row', marginTop: 30 }}> <BigInput autoFocus={true} placeholder="https://example.com" value={url || ''} onChangeValue={setUrl} style={{ flex: 1, marginRight: 10 }} + onEnter={onSubmit} /> <ButtonWithLoading - type="primary" - loading={loading} + variant="primary" + isLoading={loading} style={{ fontSize: 15 }} + onPress={onSubmit} > OK </ButtonWithLoading> {currentUrl && ( <Button - type="bare" + variant="bare" style={{ fontSize: 15, marginLeft: 10 }} - onClick={() => navigate(-1)} + onPress={() => navigate(-1)} > Cancel </Button> )} - </form> + </View> <View style={{ @@ -169,9 +165,9 @@ export function ConfigServer() { > {currentUrl ? ( <Button - type="bare" + variant="bare" style={{ color: theme.pageTextLight }} - onClick={onSkip} + onPress={onSkip} > Stop using a server </Button> @@ -179,30 +175,30 @@ export function ConfigServer() { <> {!isElectron() && ( <Button - type="bare" + variant="bare" style={{ color: theme.pageTextLight, margin: 5, marginRight: 15, }} - onClick={onSameDomain} + onPress={onSameDomain} > Use current domain </Button> )} <Button - type="bare" + variant="bare" style={{ color: theme.pageTextLight, margin: 5 }} - onClick={onSkip} + onPress={onSkip} > Don’t use a server </Button> {isNonProductionEnvironment() && ( <Button - type="primary" + variant="primary" style={{ marginLeft: 15 }} - onClick={onCreateTestFile} + onPress={onCreateTestFile} > Create test file </Button> diff --git a/packages/desktop-client/src/components/manager/DeleteFile.tsx b/packages/desktop-client/src/components/manager/DeleteFile.tsx index 3b1cff194..4fb19c856 100644 --- a/packages/desktop-client/src/components/manager/DeleteFile.tsx +++ b/packages/desktop-client/src/components/manager/DeleteFile.tsx @@ -4,7 +4,7 @@ import { type File } from 'loot-core/src/types/file'; import { type BoundActions } from '../../hooks/useActions'; import { theme } from '../../style'; -import { ButtonWithLoading } from '../common/Button'; +import { ButtonWithLoading } from '../common/Button2'; import { Modal } from '../common/Modal'; import { Text } from '../common/Text'; import { View } from '../common/View'; @@ -54,8 +54,8 @@ export function DeleteFile({ modalProps, actions, file }: DeleteFileProps) { </Text> <ButtonWithLoading - type="primary" - loading={loadingState === 'cloud'} + variant="primary" + isLoading={loadingState === 'cloud'} style={{ backgroundColor: theme.errorText, alignSelf: 'center', @@ -63,7 +63,7 @@ export function DeleteFile({ modalProps, actions, file }: DeleteFileProps) { padding: '10px 30px', fontSize: 14, }} - onClick={async () => { + onPress={async () => { setLoadingState('cloud'); await actions.deleteBudget( 'id' in file ? file.id : undefined, @@ -105,8 +105,8 @@ export function DeleteFile({ modalProps, actions, file }: DeleteFileProps) { )} <ButtonWithLoading - type={isCloudFile ? 'normal' : 'primary'} - loading={loadingState === 'local'} + variant={isCloudFile ? 'normal' : 'primary'} + isLoading={loadingState === 'local'} style={{ alignSelf: 'center', marginTop: 10, @@ -122,7 +122,7 @@ export function DeleteFile({ modalProps, actions, file }: DeleteFileProps) { backgroundColor: theme.errorText, }), }} - onClick={async () => { + onPress={async () => { setLoadingState('local'); await actions.deleteBudget(file.id); setLoadingState(null); diff --git a/packages/desktop-client/src/components/manager/Import.tsx b/packages/desktop-client/src/components/manager/Import.tsx index df9faa274..f4a1ca3bc 100644 --- a/packages/desktop-client/src/components/manager/Import.tsx +++ b/packages/desktop-client/src/components/manager/Import.tsx @@ -3,7 +3,7 @@ import React, { useState } from 'react'; import { type BoundActions } from '../../hooks/useActions'; import { styles, 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'; @@ -64,19 +64,19 @@ export function Import({ modalProps, actions }: ImportProps) { process. </Text> - <Button style={itemStyle} onClick={() => onSelectType('ynab4')}> + <Button style={itemStyle} onPress={() => onSelectType('ynab4')}> <span style={{ fontWeight: 700 }}>YNAB4</span> <View style={{ color: theme.pageTextLight }}> The old unsupported desktop app </View> </Button> - <Button style={itemStyle} onClick={() => onSelectType('ynab5')}> + <Button style={itemStyle} onPress={() => onSelectType('ynab5')}> <span style={{ fontWeight: 700 }}>nYNAB</span> <View style={{ color: theme.pageTextLight }}> <div>The newer web app</div> </View> </Button> - <Button style={itemStyle} onClick={() => onSelectType('actual')}> + <Button style={itemStyle} onPress={() => onSelectType('actual')}> <span style={{ fontWeight: 700 }}>Actual</span> <View style={{ color: theme.pageTextLight }}> <div>Import a file exported from Actual</div> diff --git a/packages/desktop-client/src/components/manager/ImportActual.tsx b/packages/desktop-client/src/components/manager/ImportActual.tsx index a6863deb5..360f7d7a4 100644 --- a/packages/desktop-client/src/components/manager/ImportActual.tsx +++ b/packages/desktop-client/src/components/manager/ImportActual.tsx @@ -6,7 +6,7 @@ import { importBudget } from 'loot-core/src/client/actions/budgets'; import { styles, theme } from '../../style'; import { Block } from '../common/Block'; -import { ButtonWithLoading } from '../common/Button'; +import { ButtonWithLoading } from '../common/Button2'; import { Modal, type ModalProps } from '../common/Modal'; import { Paragraph } from '../common/Paragraph'; import { View } from '../common/View'; @@ -83,9 +83,9 @@ export function ImportActual({ modalProps }: ImportProps) { <View style={{ alignSelf: 'center' }}> <ButtonWithLoading - type="primary" - loading={importing} - onClick={onImport} + variant="primary" + isLoading={importing} + onPress={onImport} > Select file... </ButtonWithLoading> diff --git a/packages/desktop-client/src/components/manager/ImportYNAB4.tsx b/packages/desktop-client/src/components/manager/ImportYNAB4.tsx index 338a5dd5e..e145977c8 100644 --- a/packages/desktop-client/src/components/manager/ImportYNAB4.tsx +++ b/packages/desktop-client/src/components/manager/ImportYNAB4.tsx @@ -6,7 +6,7 @@ import { importBudget } from 'loot-core/src/client/actions/budgets'; import { styles, theme } from '../../style'; import { Block } from '../common/Block'; -import { ButtonWithLoading } from '../common/Button'; +import { ButtonWithLoading } from '../common/Button2'; import { Modal, type ModalProps } from '../common/Modal'; import { Paragraph } from '../common/Paragraph'; import { View } from '../common/View'; @@ -72,9 +72,9 @@ export function ImportYNAB4({ modalProps }: ImportProps) { </Paragraph> <View> <ButtonWithLoading - type="primary" - loading={importing} - onClick={onImport} + variant="primary" + isLoading={importing} + onPress={onImport} > Select zip file... </ButtonWithLoading> diff --git a/packages/desktop-client/src/components/manager/ImportYNAB5.tsx b/packages/desktop-client/src/components/manager/ImportYNAB5.tsx index da108febd..3876f337a 100644 --- a/packages/desktop-client/src/components/manager/ImportYNAB5.tsx +++ b/packages/desktop-client/src/components/manager/ImportYNAB5.tsx @@ -6,7 +6,7 @@ import { importBudget } from 'loot-core/src/client/actions/budgets'; import { styles, theme } from '../../style'; import { Block } from '../common/Block'; -import { ButtonWithLoading } from '../common/Button'; +import { ButtonWithLoading } from '../common/Button2'; import { Link } from '../common/Link'; import { Modal, type ModalProps } from '../common/Modal'; import { Paragraph } from '../common/Paragraph'; @@ -82,9 +82,9 @@ export function ImportYNAB5({ modalProps }: ImportProps) { </Paragraph> <View> <ButtonWithLoading - type="primary" - loading={importing} - onClick={onImport} + variant="primary" + isLoading={importing} + onPress={onImport} > Select file... </ButtonWithLoading> diff --git a/packages/desktop-client/src/components/manager/WelcomeScreen.tsx b/packages/desktop-client/src/components/manager/WelcomeScreen.tsx index ce72529ec..c98f908d4 100644 --- a/packages/desktop-client/src/components/manager/WelcomeScreen.tsx +++ b/packages/desktop-client/src/components/manager/WelcomeScreen.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { useActions } from '../../hooks/useActions'; import { styles, theme } from '../../style'; -import { Button } from '../common/Button'; +import { Button } from '../common/Button2'; import { Link } from '../common/Link'; import { Paragraph } from '../common/Paragraph'; import { Text } from '../common/Text'; @@ -64,7 +64,7 @@ export function WelcomeScreen() { flexShrink: 0, }} > - <Button onClick={() => pushModal('import')}>Import my budget</Button> + <Button onPress={() => pushModal('import')}>Import my budget</Button> <View style={{ flexDirection: 'row', @@ -72,10 +72,10 @@ export function WelcomeScreen() { gap: 10, }} > - <Button onClick={() => createBudget({ testMode: true })}> + <Button onPress={() => createBudget({ testMode: true })}> View demo </Button> - <Button type="primary" onClick={() => createBudget()}> + <Button variant="primary" onPress={() => createBudget()}> Start fresh </Button> </View> diff --git a/packages/desktop-client/src/components/manager/subscribe/Bootstrap.tsx b/packages/desktop-client/src/components/manager/subscribe/Bootstrap.tsx index aa7472080..716c67425 100644 --- a/packages/desktop-client/src/components/manager/subscribe/Bootstrap.tsx +++ b/packages/desktop-client/src/components/manager/subscribe/Bootstrap.tsx @@ -7,7 +7,7 @@ import { loggedIn } from 'loot-core/src/client/actions/user'; import { send } from 'loot-core/src/platform/client/fetch'; import { theme } from '../../../style'; -import { Button } from '../../common/Button'; +import { Button } from '../../common/Button2'; import { Link } from '../../common/Link'; import { Paragraph } from '../../common/Paragraph'; import { Text } from '../../common/Text'; @@ -87,9 +87,9 @@ export function Bootstrap() { <ConfirmPasswordForm buttons={ <Button - type="bare" + variant="bare" style={{ fontSize: 15, color: theme.pageTextLink, marginRight: 15 }} - onClick={onDemo} + onPress={onDemo} > Try Demo </Button> diff --git a/packages/desktop-client/src/components/manager/subscribe/ChangePassword.tsx b/packages/desktop-client/src/components/manager/subscribe/ChangePassword.tsx index a40f0a12f..0894061e6 100644 --- a/packages/desktop-client/src/components/manager/subscribe/ChangePassword.tsx +++ b/packages/desktop-client/src/components/manager/subscribe/ChangePassword.tsx @@ -5,7 +5,7 @@ import { send } from 'loot-core/src/platform/client/fetch'; import { useNavigate } from '../../../hooks/useNavigate'; import { theme } from '../../../style'; -import { Button } from '../../common/Button'; +import { Button } from '../../common/Button2'; import { Text } from '../../common/Text'; import { View } from '../../common/View'; @@ -86,9 +86,9 @@ export function ChangePassword() { <ConfirmPasswordForm buttons={ <Button - type="bare" + variant="bare" style={{ fontSize: 15, marginRight: 10 }} - onClick={() => navigate('/')} + onPress={() => navigate('/')} > Cancel </Button> diff --git a/packages/desktop-client/src/components/manager/subscribe/ConfirmPasswordForm.tsx b/packages/desktop-client/src/components/manager/subscribe/ConfirmPasswordForm.tsx index 06ee5e668..97f40aefc 100644 --- a/packages/desktop-client/src/components/manager/subscribe/ConfirmPasswordForm.tsx +++ b/packages/desktop-client/src/components/manager/subscribe/ConfirmPasswordForm.tsx @@ -1,7 +1,7 @@ // @ts-strict-ignore -import React, { type ChangeEvent, useState } from 'react'; +import React, { useState } from 'react'; -import { ButtonWithLoading } from '../../common/Button'; +import { ButtonWithLoading } from '../../common/Button2'; import { BigInput } from '../../common/Input'; import { View } from '../../common/View'; @@ -11,8 +11,7 @@ export function ConfirmPasswordForm({ buttons, onSetPassword, onError }) { const [showPassword, setShowPassword] = useState(false); const [loading, setLoading] = useState(false); - async function onSubmit(e) { - e.preventDefault(); + async function onSubmit() { if (loading) { return; } @@ -31,32 +30,27 @@ export function ConfirmPasswordForm({ buttons, onSetPassword, onError }) { } return ( - <form + <View style={{ display: 'flex', flexDirection: 'column', alignItems: 'stretch', marginTop: 30, }} - onSubmit={onSubmit} > <BigInput autoFocus={true} placeholder="Password" type={showPassword ? 'text' : 'password'} value={password1} - onChange={(e: ChangeEvent<HTMLInputElement>) => - setPassword1(e.target.value) - } + onChangeValue={setPassword1} onEnter={onSubmit} /> <BigInput placeholder="Confirm password" type={showPassword ? 'text' : 'password'} value={password2} - onChange={(e: ChangeEvent<HTMLInputElement>) => - setPassword2(e.target.value) - } + onChangeValue={setPassword2} style={{ marginTop: 10 }} onEnter={onSubmit} /> @@ -74,10 +68,14 @@ export function ConfirmPasswordForm({ buttons, onSetPassword, onError }) { </label> <View style={{ flex: 1 }} /> {buttons} - <ButtonWithLoading type="primary" loading={loading}> + <ButtonWithLoading + variant="primary" + isLoading={loading} + onPress={onSubmit} + > OK </ButtonWithLoading> </View> - </form> + </View> ); } diff --git a/packages/desktop-client/src/components/manager/subscribe/Error.tsx b/packages/desktop-client/src/components/manager/subscribe/Error.tsx index 014046c72..c1328d43f 100644 --- a/packages/desktop-client/src/components/manager/subscribe/Error.tsx +++ b/packages/desktop-client/src/components/manager/subscribe/Error.tsx @@ -4,7 +4,7 @@ import { useLocation } from 'react-router-dom'; import { useNavigate } from '../../../hooks/useNavigate'; import { theme } from '../../../style'; -import { Button } from '../../common/Button'; +import { Button } from '../../common/Button2'; import { Text } from '../../common/Text'; import { View } from '../../common/View'; @@ -37,7 +37,7 @@ export function Error() { > {getErrorMessage(error)} </Text> - <Button onClick={onTryAgain} style={{ marginTop: 20 }}> + <Button onPress={onTryAgain} style={{ marginTop: 20 }}> Try again </Button> </View> diff --git a/packages/desktop-client/src/components/manager/subscribe/Login.tsx b/packages/desktop-client/src/components/manager/subscribe/Login.tsx index 15871a5ba..ba9546f79 100644 --- a/packages/desktop-client/src/components/manager/subscribe/Login.tsx +++ b/packages/desktop-client/src/components/manager/subscribe/Login.tsx @@ -1,5 +1,5 @@ // @ts-strict-ignore -import React, { type ChangeEvent, useState, useEffect } from 'react'; +import React, { useState, useEffect } from 'react'; import { useDispatch } from 'react-redux'; import { useParams, useSearchParams } from 'react-router-dom'; @@ -9,7 +9,7 @@ import { send } from 'loot-core/src/platform/client/fetch'; import { AnimatedLoading } from '../../../icons/AnimatedLoading'; import { theme } from '../../../style'; -import { Button, ButtonWithLoading } from '../../common/Button'; +import { Button, ButtonWithLoading } from '../../common/Button2'; import { BigInput } from '../../common/Input'; import { Link } from '../../common/Link'; import { Text } from '../../common/Text'; @@ -63,8 +63,7 @@ export function Login() { } } - async function onSubmit(e) { - e.preventDefault(); + async function onSubmit() { if (password === '' || loading) { return; } @@ -120,27 +119,24 @@ export function Login() { )} {method === 'password' && ( - <form - style={{ display: 'flex', flexDirection: 'row', marginTop: 30 }} - onSubmit={onSubmit} - > + <View style={{ display: 'flex', flexDirection: 'row', marginTop: 30 }}> <BigInput autoFocus={true} placeholder="Password" type="password" - onChange={(e: ChangeEvent<HTMLInputElement>) => - setPassword(e.target.value) - } + onChangeValue={setPassword} style={{ flex: 1, marginRight: 10 }} + onEnter={onSubmit} /> <ButtonWithLoading - type="primary" - loading={loading} + variant="primary" + isLoading={loading} style={{ fontSize: 15 }} + onPress={onSubmit} > Sign in </ButtonWithLoading> - </form> + </View> )} {method === 'header' && ( <View @@ -176,9 +172,9 @@ export function Login() { }} > <Button - type="bare" + variant="bare" style={{ fontSize: 15, color: theme.pageTextLink, marginLeft: 10 }} - onClick={onDemo} + onPress={onDemo} > Try Demo → </Button> diff --git a/upcoming-release-notes/2916.md b/upcoming-release-notes/2916.md new file mode 100644 index 000000000..9033f8556 --- /dev/null +++ b/upcoming-release-notes/2916.md @@ -0,0 +1,6 @@ +--- +category: Maintenance +authors: [joel-jeremy] +--- + +Use new react-aria-components based Button on management components. -- GitLab