a11y: aria-pressed
Massimo Melina committed
Jan 11, 2024 at 23:52 UTC
009d0015772b6bf119ee90894f0425a2beb60e45
5 files changed
+19
-18
admin/src/LogsPage.ts
+1
-1
@@ -17,7 +17,7 @@ export default function LogsPage() {
17
const files = typedKeys(logLabels)
18
const { pause, pauseButton } = usePauseButton()
19
const [showApi, showApiButton] = useToggleButton(v => ({
20
- title: v ? "hide APIs" : "show APIs",
20
+ title: "Show/hide APIs",
21
icon: SmartToy,
22
sx: { rotate: v ? '0deg' : '180deg' },
23
disabled: tab >= 2,
admin/src/mui.ts
+2
-1
@@ -207,7 +207,7 @@ export function LinkBtn({ ...rest }: LinkProps) {
207
208
export function usePauseButton() {
209
const [go, btn] = useToggleButton(v => ({
210
- title: v ? "Pause" : "Resume",
210
+ title: "Pause",
211
icon: v ? PauseCircle : PlayCircle,
212
sx: { rotate: v ? '180deg' : '0deg' },
213
}), true)
@@ -221,6 +221,7 @@ export function useToggleButton(iconBtn: (state:boolean) => Omit<IconBtnProps, '
221
const el = h(IconBtn, {
222
size: 'small',
223
color: state ? 'primary' : 'default',
224
+ 'aria-pressed': state,
225
...props,
226
sx: { transition: 'all .5s', ...props.sx },
227
onClick: toggle,
frontend/src/UserPanel.ts
+3
-3
@@ -6,7 +6,7 @@ import { alertDialog, closeDialog, newDialog, promptDialog } from './dialog'
6
import { createVerifierAndSalt, SRPParameters, SRPRoutines } from 'tssrp6a'
7
import { apiCall } from '@hfs/shared/api'
8
import { logout } from './login'
9
-import { MenuButton } from './menu'
9
+import { Btn } from './menu'
10
import { hIcon, HTTP_NOT_ACCEPTABLE, working } from './misc'
11
import { t } from './i18n'
12
import { CustomCode } from './components'
@@ -21,7 +21,7 @@ export default function showUserPanel() {
21
return h('div', { id: 'user-panel' },
22
h('div', {}, t`Username`, ': ', snap.username),
23
h(CustomCode, { name: 'userPanelAfterInfo' }),
24
- snap.canChangePassword && h(MenuButton, {
24
+ snap.canChangePassword && h(Btn, {
25
icon: 'password',
26
label: t`Change password`,
27
id: 'change-password',
@@ -48,7 +48,7 @@ export default function showUserPanel() {
48
}
49
}
50
}),
51
- h(MenuButton, {
51
+ h(Btn, {
52
icon: 'logout',
53
label: t`Logout`,
54
id: 'logout',
frontend/src/clip.ts
+4
-4
@@ -1,6 +1,6 @@
1
import { createElement as h, Fragment } from 'react'
2
import { DirList, state, useSnapState } from './state'
3
-import { MenuButton } from './menu'
3
+import { Btn } from './menu'
4
import { t, useI18N } from './i18n'
5
import { alertDialog } from './dialog'
6
import { useNavigate } from 'react-router-dom'
@@ -18,9 +18,9 @@ export function ClipBar() {
18
return null
19
const there = dirname(clip[0].uri) + '/'
20
return h('div', { id: 'clipBar' },
21
- h(MenuButton, { label: t`Cancel clipboard`, icon: 'close', onClick: cancel }),
22
- h(MenuButton, { label: t('to_clipboard_source', "To folder"), icon: 'parent', onClick: goBack, disabled: here === there }),
23
- h(MenuButton, { label: t`Paste`, icon: 'paste', onClick: paste, disabled: here === there || !props?.can_upload }),
21
+ h(Btn, { label: t`Cancel clipboard`, icon: 'close', onClick: cancel }),
22
+ h(Btn, { label: t('to_clipboard_source', "To folder"), icon: 'parent', onClick: goBack, disabled: here === there }),
23
+ h(Btn, { label: t`Paste`, icon: 'paste', onClick: paste, disabled: here === there || !props?.can_upload }),
24
h('div', { onClick: show, style: { flex: 1 } },
25
clip.length === 1 ? clip[0].name : t('n_items', { n: clip.length }, "{n,plural, one{# item} other{# items}}") ),
26
)
frontend/src/menu.ts
+9
-9
@@ -1,13 +1,12 @@
1
// This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
2
3
-import { DirList, state, useSnapState } from './state'
3
+import { state, useSnapState } from './state'
4
import { ComponentPropsWithoutRef, createElement as h, Fragment, useEffect, useMemo, useState } from 'react'
5
import { alertDialog, confirmDialog, ConfirmOptions, promptDialog } from './dialog'
6
import { defaultPerms, err2msg, ErrorMsg, hIcon, onlyTruthy, prefix, useStateMounted, VfsPerms, working } from './misc'
7
import { loginDialog } from './login'
8
import { showOptions } from './options'
9
import showUserPanel from './UserPanel'
10
-import { useNavigate } from 'react-router-dom'
10
import _ from 'lodash'
11
import { closeDialog } from '@hfs/shared/dialogs'
12
import { showUpload, uploadState } from './upload'
@@ -48,7 +47,7 @@ export function MenuPanel() {
47
return h('div', { id: 'menu-panel' },
48
h('div', { id: 'menu-bar' },
49
h(LoginButton),
51
- h(MenuButton, {
50
+ h(Btn, {
51
id: 'select-button',
52
icon: 'check',
53
label: t`Select`,
@@ -58,7 +57,7 @@ export function MenuPanel() {
57
state.showFilter = !showFilter
58
}
59
}),
61
- h(MenuButton, changingButton === 'delete' ? {
60
+ h(Btn, changingButton === 'delete' ? {
61
id: 'delete-button',
62
icon: 'delete',
63
label: t`Delete`,
@@ -73,7 +72,7 @@ export function MenuPanel() {
72
className: changingButton ? 'show-sliding ' + (uploading ? 'ani-working' : '') : 'before-sliding',
73
onClick: showUpload,
74
}),
76
- h(MenuButton, showFilter && can_delete ? {
75
+ h(Btn, showFilter && can_delete ? {
76
id: 'cut-button',
77
icon: 'cut',
78
label: t`Cut`,
@@ -81,7 +80,7 @@ export function MenuPanel() {
80
cut(onlyTruthy(Object.keys(selected).map(uri => _.find(state.list, { uri }))))
81
}
82
} : getSearchProps()),
84
- h(MenuButton, {
83
+ h(Btn, {
84
id: 'options-button',
85
icon: 'settings',
86
label: t`Options`,
@@ -157,7 +156,7 @@ interface MenuButtonProps extends ComponentPropsWithoutRef<"button"> {
156
onClickAnimation?: boolean
157
}
158
160
-export function MenuButton({ icon, label, tooltip, toggled, onClick, onClickAnimation, ...rest }: MenuButtonProps) {
159
+export function Btn({ icon, label, tooltip, toggled, onClick, onClickAnimation, ...rest }: MenuButtonProps) {
160
const [working, setWorking] = useState(false)
161
return h('button', {
162
title: tooltip || label,
@@ -168,6 +167,7 @@ export function MenuButton({ icon, label, tooltip, toggled, onClick, onClickAnim
167
Promise.resolve(onClick()).finally(() => setWorking(false))
168
},
169
className: [rest.className, toggled && 'toggled', working && 'ani-working'].filter(Boolean).join(' '),
170
+ ...toggled !== undefined && { 'aria-pressed': toggled },
171
...rest,
172
}, hIcon(icon), h('label', {}, label) )
173
}
@@ -182,13 +182,13 @@ export function MenuLink({ href, target, confirm, confirmOptions, ...rest }: Men
182
ev.preventDefault()
183
await confirmDialog(confirm, { href, title: t`Confirm`, ...confirmOptions })
184
}
185
- }, h(MenuButton, rest))
185
+ }, h(Btn, rest))
186
}
187
188
function LoginButton() {
189
const snap = useSnapState()
190
const {t} = useI18N()
191
- return MenuButton(snap.username ? {
191
+ return Btn(snap.username ? {
192
id: 'user-button',
193
toggled: true,
194
icon: 'user',