diff options
| author | 2025-04-09 14:14:20 +0200 | |
|---|---|---|
| committer | 2025-04-09 14:14:20 +0200 | |
| commit | 19cfa8d126a2ff54298150529e58e5e4f5495f09 (patch) | |
| tree | 3a569e6c456cc7ea13f16f04c5cd81301b71e5f2 /web/source/settings/components | |
| parent | [feature] add TOTP two-factor authentication (2FA) (#3960) (diff) | |
| download | gotosocial-19cfa8d126a2ff54298150529e58e5e4f5495f09.tar.xz | |
[bugfix] Fix a couple accessibility issues with `:focus` elements (#3979)
* [bugfix/frontend] Fix accessibility/focus issues in settings + web ui
* fix little error
* tweaks
Diffstat (limited to 'web/source/settings/components')
| -rw-r--r-- | web/source/settings/components/form/inputs.tsx | 29 | ||||
| -rw-r--r-- | web/source/settings/components/status.tsx | 64 | ||||
| -rw-r--r-- | web/source/settings/components/username-lozenge.tsx | 22 |
3 files changed, 83 insertions, 32 deletions
diff --git a/web/source/settings/components/form/inputs.tsx b/web/source/settings/components/form/inputs.tsx index 498499db6..c26b88f6a 100644 --- a/web/source/settings/components/form/inputs.tsx +++ b/web/source/settings/components/form/inputs.tsx @@ -17,7 +17,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ -import React from "react"; +import React, { useRef } from "react"; import type { ReactNode, @@ -119,23 +119,36 @@ export interface FileInputProps extends React.DetailedHTMLProps< } export function FileInput({ label, field, ...props }: FileInputProps) { - const { onChange, ref, infoComponent } = field; + const ref = useRef<HTMLInputElement>(null); + const { onChange, infoComponent } = field; const id = nanoid(); + const onClick = () => { + ref.current?.click(); + }; return ( <div className="form-field file"> - <label className="label-label" htmlFor={id}> - {label} - </label> - <label className="label-button" htmlFor={id}> - <div className="file-input button">Browse</div> + <label + className="label-wrapper" + htmlFor={id} + tabIndex={0} + onClick={onClick} + onKeyDown={e => e.key === "Enter" && onClick()} + role="button" + > + <div className="label-label"> + {label} + </div> + <div className="label-button"> + <div className="file-input button">Browse</div> + </div> </label> <input id={id} type="file" className="hidden" onChange={onChange} - ref={ref ? ref as RefObject<HTMLInputElement> : undefined} + ref={ref} {...props} /> {infoComponent} diff --git a/web/source/settings/components/status.tsx b/web/source/settings/components/status.tsx index 701a9f8b7..04c5933d5 100644 --- a/web/source/settings/components/status.tsx +++ b/web/source/settings/components/status.tsx @@ -17,7 +17,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ -import React from "react"; +import React, { useRef } from "react"; import { useVerifyCredentialsQuery } from "../lib/query/login"; import { MediaAttachment, Status as StatusType } from "../lib/types/status"; import sanitize from "sanitize-html"; @@ -122,10 +122,26 @@ function StatusBody({ status }: { status: StatusType }) { content = sanitize(status.content); } + const detailsRef = useRef<HTMLDetailsElement>(null); + const detailsOnClick = () => { + detailsRef.current?.click(); + }; + + const summaryRef = useRef<HTMLElement>(null); + const summaryOnClick = () => { + summaryRef.current?.click(); + }; + return ( <div className="status-body"> - <details className="text-spoiler"> - <summary> + <details + className="text-spoiler" + ref={detailsRef} + > + <summary + tabIndex={-1} + ref={summaryRef} + > <div className="spoiler-content" lang={status.language} @@ -140,6 +156,8 @@ function StatusBody({ status }: { status: StatusType }) { role="button" tabIndex={0} aria-label="Toggle content visibility" + onClick={detailsOnClick} + onKeyDown={e => e.key === "Enter" && summaryOnClick()} > Toggle content visibility </span> @@ -183,23 +201,41 @@ function StatusMedia({ status }: { status: StatusType }) { } function StatusMediaEntry({ media }: { media: MediaAttachment }) { + const detailsRef = useRef<HTMLDetailsElement>(null); + const detailsOnClick = () => { + detailsRef.current?.click(); + }; + + const summaryRef = useRef<HTMLElement>(null); + const summaryOnClick = () => { + summaryRef.current?.click(); + }; + return ( <div className="media-wrapper"> <details className="image-spoiler media-spoiler"> - <summary> - <div className="show sensitive button" aria-hidden="true">Show media</div> - <span className="eye button" role="button" tabIndex={0} aria-label="Toggle show media"> + <summary tabIndex={-1} ref={summaryRef}> + <div + className="show sensitive button" + role="button" + tabIndex={0} + aria-hidden="true" + onClick={detailsOnClick} + onKeyDown={e => e.key === "Enter" && summaryOnClick()} + > + Show media + </div> + <span + className="eye button" + role="button" + tabIndex={0} + aria-label="Toggle show media" + onClick={detailsOnClick} + onKeyDown={e => e.key === "Enter" && summaryOnClick()} + > <i className="hide fa fa-fw fa-eye-slash" aria-hidden="true"></i> <i className="show fa fa-fw fa-eye" aria-hidden="true"></i> </span> - <img - src={media.preview_url} - loading="lazy" - alt={media.description} - title={media.description} - width={media.meta.small.width} - height={media.meta.small.height} - /> </summary> <a href={media.url} diff --git a/web/source/settings/components/username-lozenge.tsx b/web/source/settings/components/username-lozenge.tsx index 9f955cf22..44d627ed3 100644 --- a/web/source/settings/components/username-lozenge.tsx +++ b/web/source/settings/components/username-lozenge.tsx @@ -150,19 +150,21 @@ function ReadyUsernameLozenge({ account, linkTo, backLocation, classNames }: Rea if (linkTo) { className += " pseudolink"; + const onClick = () => { + // When clicking on an account, direct + // to the detail view for that account. + setLocation(linkTo, { + // Store the back location in history so + // the detail view can use it to return to + // this page (including query parameters). + state: { backLocation: backLocation } + }); + }; return ( <span className={className} - onClick={() => { - // When clicking on an account, direct - // to the detail view for that account. - setLocation(linkTo, { - // Store the back location in history so - // the detail view can use it to return to - // this page (including query parameters). - state: { backLocation: backLocation } - }); - }} + onClick={onClick} + onKeyDown={e => e.key === "Enter" && onClick()} role="link" tabIndex={0} > |
