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',