diff --git a/fluxer_app/src/features/app/components/layout/KeyboardModeListener.ts b/fluxer_app/src/features/app/components/layout/KeyboardModeListener.ts index a11b3a6e7..cb6ab8b9e 100644 --- a/fluxer_app/src/features/app/components/layout/KeyboardModeListener.ts +++ b/fluxer_app/src/features/app/components/layout/KeyboardModeListener.ts @@ -1,7 +1,11 @@ // SPDX-License-Identifier: AGPL-3.0-or-later import {Routes} from '@app/app/Routes'; -import {CHANNEL_TEXTAREA_SELECTOR} from '@app/features/app/keybindings/utils/EditableElement'; +import { + CHANNEL_TEXTAREA_SELECTOR, + isChannelTextareaElement, + isEditableElement, +} from '@app/features/app/keybindings/utils/EditableElement'; import {useLocation} from '@app/features/platform/components/router/RouterReact'; import {ComponentBus} from '@app/features/platform/utils/ComponentBus'; import FocusRingManager from '@app/features/ui/focus_ring/FocusRingManager'; @@ -29,6 +33,7 @@ const canRedirectTabToComposer = (composer: HTMLTextAreaElement | null): compose if (composer == null || composer.disabled || composer.getAttribute('aria-disabled') === 'true') return false; if (isElementInert(composer)) return false; const active = document.activeElement; + if (isEditableElement(active) && !isChannelTextareaElement(active)) return false; return !(active instanceof Element && active.closest(FOCUS_TRAPPING_OVERLAY_SELECTOR) != null); }; diff --git a/fluxer_app/src/features/threads/components/ThreadCreatePane.tsx b/fluxer_app/src/features/threads/components/ThreadCreatePane.tsx index d1eb714ff..be2b4d17a 100644 --- a/fluxer_app/src/features/threads/components/ThreadCreatePane.tsx +++ b/fluxer_app/src/features/threads/components/ThreadCreatePane.tsx @@ -11,6 +11,7 @@ import {CloudUpload} from '@app/features/messaging/upload/CloudUpload'; import * as MessageSubmitUtils from '@app/features/messaging/utils/MessageSubmitUtils'; import {formatUploadingAttachmentSummary} from '@app/features/messaging/utils/UploadingAttachmentLabelUtils'; import Permission from '@app/features/permissions/state/Permission'; +import {shouldDisableAutofocusOnMobile} from '@app/features/platform/utils/AutofocusUtils'; import * as ThreadCommands from '@app/features/threads/commands/ThreadCommands'; import {openThread} from '@app/features/threads/commands/ThreadNavigation'; import styles from '@app/features/threads/components/ThreadCreatePane.module.css'; @@ -71,6 +72,23 @@ export const ThreadCreatePane = observer(({parent, messageId}: ThreadCreatePaneP const [isPrivate, setIsPrivate] = useState(false); const nameRef = useRef(name); nameRef.current = name; + const nameInputRef = useRef(null); + useEffect(() => { + const input = nameInputRef.current; + if (!input || shouldDisableAutofocusOnMobile()) return; + const inertRoot = input.closest('[inert]'); + if (!inertRoot) { + input.focus(); + return; + } + const observer = new MutationObserver(() => { + if (input.closest('[inert]')) return; + observer.disconnect(); + input.focus(); + }); + observer.observe(inertRoot, {attributes: true, attributeFilter: ['inert']}); + return () => observer.disconnect(); + }, []); const sourceMessage = messageId ? Messages.getMessage(parent.id, messageId) : undefined; const draftKey = `thread-create:${parent.id}`; const accountKey = Users.viewAccountKey; @@ -138,6 +156,7 @@ export const ThreadCreatePane = observer(({parent, messageId}: ThreadCreatePaneP { setName(event.target.value); @@ -146,7 +165,6 @@ export const ThreadCreatePane = observer(({parent, messageId}: ThreadCreatePaneP label={i18n._(D.THREAD_NAME_DESCRIPTOR)} placeholder={sourceMessage?.content.slice(0, THREAD_NAME_MAX_LENGTH) || i18n._(D.NEW_THREAD_DESCRIPTOR)} maxLength={THREAD_NAME_MAX_LENGTH} - autoFocus autoComplete="off" error={nameError} data-flx="threads.thread-create-pane.input.name"