diff --git a/examples/01-basic/04-default-blocks/src/App.tsx b/examples/01-basic/04-default-blocks/src/App.tsx index 0d55d1af3d..872555abd7 100644 --- a/examples/01-basic/04-default-blocks/src/App.tsx +++ b/examples/01-basic/04-default-blocks/src/App.tsx @@ -2,6 +2,8 @@ import "@blocknote/core/fonts/inter.css"; import { BlockNoteView } from "@blocknote/mantine"; import "@blocknote/mantine/style.css"; import { useCreateBlockNote } from "@blocknote/react"; +import { Button, Popover, Text, TextInput } from "@mantine/core"; +import { useRef } from "react"; export default function App() { // Creates a new editor instance. @@ -148,6 +150,8 @@ export default function App() { ], }); + const inputRef = useRef(null); + // Renders the editor instance using a React component. return ; } diff --git a/packages/ariakit/src/input/TextInput.tsx b/packages/ariakit/src/input/TextInput.tsx index 555961faf0..0f3019e208 100644 --- a/packages/ariakit/src/input/TextInput.tsx +++ b/packages/ariakit/src/input/TextInput.tsx @@ -23,6 +23,7 @@ export const TextInput = forwardRef< disabled, onKeyDown, onChange, + onClickCapture, onSubmit, autoComplete, "aria-activedescendant": ariaActivedescendant, @@ -51,6 +52,7 @@ export const TextInput = forwardRef< disabled={disabled} onKeyDown={onKeyDown} onChange={onChange} + onClickCapture={onClickCapture} onSubmit={onSubmit} autoComplete={autoComplete} aria-activedescendant={ariaActivedescendant} diff --git a/packages/mantine/src/blocknoteStyles.css b/packages/mantine/src/blocknoteStyles.css index e23396b40e..e44cd899ff 100644 --- a/packages/mantine/src/blocknoteStyles.css +++ b/packages/mantine/src/blocknoteStyles.css @@ -254,6 +254,19 @@ font-size: 12px; } +/* On touch devices, enlarge the form-popover inputs (e.g. the link popover's + URL field). The 16px font-size is load-bearing: iOS Safari auto-zooms the + page when focusing an input with a smaller computed font-size, and that zoom + perturbs the visual viewport the mobile toolbar positions itself from. The + taller min-height also gives a comfortable tap target. */ +@media (pointer: coarse) { + .bn-form-popover .mantine-TextInput-input, + .bn-form-popover .mantine-FileInput-input { + font-size: 16px; + min-height: 40px; + } +} + .bn-form-popover .mantine-FileInput-input:hover { background-color: var(--bn-colors-hovered-background); } diff --git a/packages/mantine/src/form/TextInput.tsx b/packages/mantine/src/form/TextInput.tsx index c1630fa17f..3bd844145d 100644 --- a/packages/mantine/src/form/TextInput.tsx +++ b/packages/mantine/src/form/TextInput.tsx @@ -20,6 +20,7 @@ export const TextInput = forwardRef< disabled, onKeyDown, onChange, + onClickCapture, onSubmit, autoComplete, "aria-activedescendant": ariaActivedescendant, @@ -48,6 +49,7 @@ export const TextInput = forwardRef< disabled={disabled} onKeyDown={onKeyDown} onChange={onChange} + onClickCapture={onClickCapture} onSubmit={onSubmit} autoComplete={autoComplete} aria-activedescendant={ariaActivedescendant} diff --git a/packages/react/src/components/LinkToolbar/EditLinkMenuItems.tsx b/packages/react/src/components/LinkToolbar/EditLinkMenuItems.tsx index 1d82a6e7cc..2145ff641e 100644 --- a/packages/react/src/components/LinkToolbar/EditLinkMenuItems.tsx +++ b/packages/react/src/components/LinkToolbar/EditLinkMenuItems.tsx @@ -6,12 +6,14 @@ import { import { ChangeEvent, KeyboardEvent, + MouseEvent, useCallback, useEffect, useState, } from "react"; import { RiLink, RiText } from "react-icons/ri"; import { useComponentsContext } from "../../editor/ComponentsContext.js"; +import { useBlockNoteEditor } from "../../hooks/useBlockNoteEditor.js"; import { useExtension } from "../../hooks/useExtension.js"; import { useDictionary } from "../../i18n/dictionary.js"; import { LinkToolbarProps } from "./LinkToolbarProps.js"; @@ -36,6 +38,7 @@ export const EditLinkMenuItems = ( ) => { const Components = useComponentsContext()!; const dict = useDictionary(); + const editor = useBlockNoteEditor(); // eslint-disable-next-line @typescript-eslint/unbound-method -- editLink is a plain object method, not a class method const { editLink } = useExtension(LinkToolbarExtension); @@ -80,6 +83,19 @@ export const EditLinkMenuItems = ( props.setToolbarPositionFrozen?.(false); }, [editLink, currentUrl, currentText, props]); + // Scrolling the input into view works around an Android Chrome issue where + // the input is otherwise left hidden behind the on-screen keyboard. We then + // restore the scroll position to the editor selection. + const handleClickCapture = useCallback( + (event: MouseEvent) => { + event.currentTarget.scrollIntoView(); + setTimeout(() => { + editor.transact((tr) => tr.scrollIntoView()); + }, 1000); + }, + [editor], + ); + return ( {/* // TODO: add labels? */} @@ -87,11 +103,12 @@ export const EditLinkMenuItems = ( className={"bn-text-input"} name="url" icon={} - autoFocus={true} + autoFocus={false} placeholder={dict.link_toolbar.form.url_placeholder} value={currentUrl} onKeyDown={handleEnter} onChange={handleUrlChange} + onClickCapture={handleClickCapture} onSubmit={handleSubmit} /> {showTextField !== false && ( @@ -103,6 +120,7 @@ export const EditLinkMenuItems = ( value={currentText} onKeyDown={handleEnter} onChange={handleTextChange} + onClickCapture={handleClickCapture} onSubmit={handleSubmit} /> )} diff --git a/packages/react/src/editor/ComponentsContext.tsx b/packages/react/src/editor/ComponentsContext.tsx index 4b60483d43..53f0a9b00d 100644 --- a/packages/react/src/editor/ComponentsContext.tsx +++ b/packages/react/src/editor/ComponentsContext.tsx @@ -317,6 +317,7 @@ export type ComponentProps = { value: string; onKeyDown: (event: KeyboardEvent) => void; onChange: (event: ChangeEvent) => void; + onClickCapture?: (event: MouseEvent) => void; onSubmit?: () => void; autoComplete?: HTMLInputAutoCompleteAttribute; "aria-activedescendant"?: string; diff --git a/packages/shadcn/src/form/TextInput.tsx b/packages/shadcn/src/form/TextInput.tsx index 675e7409fa..56ec10be0b 100644 --- a/packages/shadcn/src/form/TextInput.tsx +++ b/packages/shadcn/src/form/TextInput.tsx @@ -21,6 +21,7 @@ export const TextInput = forwardRef< disabled, onKeyDown, onChange, + onClickCapture, onSubmit, autoComplete: _autoComplete, "aria-activedescendant": ariaActivedescendant, @@ -57,6 +58,7 @@ export const TextInput = forwardRef< value={value} onKeyDown={onKeyDown} onChange={onChange} + onClickCapture={onClickCapture} onSubmit={onSubmit} ref={ref} aria-activedescendant={ariaActivedescendant}