Skip to content
Open
18 changes: 16 additions & 2 deletions packages/ariakit/src/input/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,23 @@ import { assertEmpty } from "@blocknote/core";
import { ComponentProps } from "@blocknote/react";

export const Form = (props: ComponentProps["Generic"]["Form"]["Root"]) => {
const { children, ...rest } = props;
const { children, onSubmit, submitButton, ...rest } = props;

assertEmpty(rest);

return <AriakitFormProvider>{children}</AriakitFormProvider>;
return (
<AriakitFormProvider>
<form
className={"bn-form"}
onSubmit={(event) => {
// These forms have no action — a real submission would navigate.
event.preventDefault();
onSubmit?.();
}}
>
{children}
{submitButton === "none" ? null : submitButton}
</form>
</AriakitFormProvider>
);
};
12 changes: 7 additions & 5 deletions packages/ariakit/src/input/TextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
} from "@ariakit/react";

import { assertEmpty, mergeCSSClasses } from "@blocknote/core";
import { ComponentProps } from "@blocknote/react";
import { ComponentProps, useMergeRefs, useAutoFocus } from "@blocknote/react";
import { forwardRef } from "react";

export const TextInput = forwardRef<
Expand All @@ -23,7 +23,6 @@ export const TextInput = forwardRef<
disabled,
onKeyDown,
onChange,
onSubmit,
autoComplete,
"aria-activedescendant": ariaActivedescendant,
rightSection,
Expand All @@ -32,6 +31,11 @@ export const TextInput = forwardRef<

assertEmpty(rest);

// Rationale (and the trap contract `data-autofocus` serves) in the hook.

const inputRef = useAutoFocus<HTMLInputElement>(autoFocus);
const setRefs = useMergeRefs([inputRef, ref]);

return (
<>
{props.label && <AriakitFormLabel name={name}>{label}</AriakitFormLabel>}
Expand All @@ -43,15 +47,13 @@ export const TextInput = forwardRef<
className || "",
variant === "large" ? "bn-ak-input-large" : "",
)}
ref={ref}
ref={setRefs}
name={name}
value={value}
autoFocus={autoFocus}
placeholder={placeholder}
disabled={disabled}
onKeyDown={onKeyDown}
onChange={onChange}
onSubmit={onSubmit}
autoComplete={autoComplete}
aria-activedescendant={ariaActivedescendant}
/>
Expand Down
3 changes: 2 additions & 1 deletion packages/ariakit/src/panel/PanelButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ export const PanelButton = forwardRef<
HTMLButtonElement,
ComponentProps["FilePanel"]["Button"]
>((props, ref) => {
const { className, children, onClick, label, ...rest } = props;
const { className, children, type, onClick, label, ...rest } = props;

assertEmpty(rest);

return (
<AriakitButton
type={type}
className={mergeCSSClasses("bn-ak-button", className || "")}
onClick={onClick}
aria-label={label}
Expand Down
6 changes: 6 additions & 0 deletions packages/ariakit/src/popover/Popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ export const PopoverContent = forwardRef<
className || "",
variant === "panel-popover" ? "bn-ak-panel-popover" : "",
)}
// BlockNote owns focus in its popovers (useAutoFocus, which prevents
// scrolling). Ariakit's default would bare-focus the first tabbable —
// in form popovers the very input the hook handles, re-introducing
// the scroll-yank it exists to avoid. No other skin's library moves
// focus to an input on open either.
autoFocusOnShow={false}
portalElement={portalRoot ?? undefined}
ref={ref}
>
Expand Down
8 changes: 7 additions & 1 deletion packages/core/src/editor/managers/StyleManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,13 @@ export class StyleManager<
*/
public getSelectedLinkUrl() {
return this.editor.transact((tr) => {
return this.getLinkMarkAtPos(tr.selection.from)?.href;
// `from + 1` for the same boundary reason as `editLink` below: at the
// left edge of a link (e.g. when the whole link is selected), the mark
// lookup at `from` itself misses the mark and the link's URL would
// incorrectly read as absent.
return this.getLinkMarkAtPos(
Math.min(tr.selection.from + 1, tr.doc.content.size),
)?.href;
});
}

Expand Down
1 change: 1 addition & 0 deletions packages/core/src/i18n/locales/ar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -406,5 +406,6 @@ export const ar: Dictionary = {
},
generic: {
ctrl_shortcut: "Ctrl",
form_submit: "موافق",
},
};
1 change: 1 addition & 0 deletions packages/core/src/i18n/locales/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -440,5 +440,6 @@ export const de: Dictionary = {
},
generic: {
ctrl_shortcut: "Strg",
form_submit: "OK",
},
};
1 change: 1 addition & 0 deletions packages/core/src/i18n/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -421,5 +421,6 @@ export const en = {
},
generic: {
ctrl_shortcut: "Ctrl",
form_submit: "OK",
},
};
1 change: 1 addition & 0 deletions packages/core/src/i18n/locales/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -419,5 +419,6 @@ export const es: Dictionary = {
},
generic: {
ctrl_shortcut: "Ctrl",
form_submit: "Aceptar",
},
};
1 change: 1 addition & 0 deletions packages/core/src/i18n/locales/fa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -390,5 +390,6 @@ export const fa = {
},
generic: {
ctrl_shortcut: "Ctrl",
form_submit: "تأیید",
},
};
1 change: 1 addition & 0 deletions packages/core/src/i18n/locales/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -467,5 +467,6 @@ export const fr: Dictionary = {
},
generic: {
ctrl_shortcut: "Ctrl",
form_submit: "OK",
},
};
1 change: 1 addition & 0 deletions packages/core/src/i18n/locales/he.ts
Original file line number Diff line number Diff line change
Expand Up @@ -421,5 +421,6 @@ export const he: Dictionary = {
},
generic: {
ctrl_shortcut: "Ctrl",
form_submit: "אישור",
},
};
1 change: 1 addition & 0 deletions packages/core/src/i18n/locales/hr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -435,5 +435,6 @@ export const hr: Dictionary = {
},
generic: {
ctrl_shortcut: "Ctrl",
form_submit: "U redu",
},
};
1 change: 1 addition & 0 deletions packages/core/src/i18n/locales/is.ts
Original file line number Diff line number Diff line change
Expand Up @@ -435,5 +435,6 @@ export const is: Dictionary = {
},
generic: {
ctrl_shortcut: "Ctrl",
form_submit: "Í lagi",
},
};
1 change: 1 addition & 0 deletions packages/core/src/i18n/locales/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -443,5 +443,6 @@ export const it: Dictionary = {
},
generic: {
ctrl_shortcut: "Ctrl",
form_submit: "OK",
},
};
1 change: 1 addition & 0 deletions packages/core/src/i18n/locales/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -461,5 +461,6 @@ export const ja: Dictionary = {
},
generic: {
ctrl_shortcut: "Ctrl",
form_submit: "OK",
},
};
1 change: 1 addition & 0 deletions packages/core/src/i18n/locales/ko.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,5 +434,6 @@ export const ko: Dictionary = {
},
generic: {
ctrl_shortcut: "Ctrl",
form_submit: "확인",
},
};
1 change: 1 addition & 0 deletions packages/core/src/i18n/locales/nl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,5 +422,6 @@ export const nl: Dictionary = {
},
generic: {
ctrl_shortcut: "Ctrl",
form_submit: "OK",
},
};
1 change: 1 addition & 0 deletions packages/core/src/i18n/locales/no.ts
Original file line number Diff line number Diff line change
Expand Up @@ -439,5 +439,6 @@ export const no: Dictionary = {
},
generic: {
ctrl_shortcut: "Ctrl",
form_submit: "OK",
},
};
1 change: 1 addition & 0 deletions packages/core/src/i18n/locales/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -412,5 +412,6 @@ export const pl: Dictionary = {
},
generic: {
ctrl_shortcut: "Ctrl",
form_submit: "OK",
},
};
1 change: 1 addition & 0 deletions packages/core/src/i18n/locales/pt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -414,5 +414,6 @@ export const pt: Dictionary = {
},
generic: {
ctrl_shortcut: "Ctrl",
form_submit: "OK",
},
};
1 change: 1 addition & 0 deletions packages/core/src/i18n/locales/ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -465,5 +465,6 @@ export const ru: Dictionary = {
},
generic: {
ctrl_shortcut: "Ctrl",
form_submit: "ОК",
},
};
1 change: 1 addition & 0 deletions packages/core/src/i18n/locales/sk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -419,5 +419,6 @@ export const sk = {
},
generic: {
ctrl_shortcut: "Ctrl",
form_submit: "OK",
},
};
1 change: 1 addition & 0 deletions packages/core/src/i18n/locales/uk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -445,5 +445,6 @@ export const uk: Dictionary = {
},
generic: {
ctrl_shortcut: "Ctrl",
form_submit: "ОК",
},
};
1 change: 1 addition & 0 deletions packages/core/src/i18n/locales/uz.ts
Original file line number Diff line number Diff line change
Expand Up @@ -455,5 +455,6 @@ export const uz: Dictionary = {
},
generic: {
ctrl_shortcut: "Ctrl",
form_submit: "OK",
},
};
1 change: 1 addition & 0 deletions packages/core/src/i18n/locales/vi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -420,5 +420,6 @@ export const vi: Dictionary = {
},
generic: {
ctrl_shortcut: "Ctrl",
form_submit: "OK",
},
};
1 change: 1 addition & 0 deletions packages/core/src/i18n/locales/zh-tw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -462,5 +462,6 @@ export const zhTW: Dictionary = {
},
generic: {
ctrl_shortcut: "Ctrl",
form_submit: "確定",
},
};
1 change: 1 addition & 0 deletions packages/core/src/i18n/locales/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -462,5 +462,6 @@ export const zh: Dictionary = {
},
generic: {
ctrl_shortcut: "Ctrl",
form_submit: "确定",
},
};
13 changes: 13 additions & 0 deletions packages/mantine/src/blocknoteStyles.css
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,19 @@ on touch devices (e.g. the mobile formatting toolbar). */
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. (From #2982.) */
@media (pointer: coarse) {
Comment thread
YousefED marked this conversation as resolved.
.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);
}
Expand Down
3 changes: 2 additions & 1 deletion packages/mantine/src/components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Badge, BadgeGroup } from "./badge/Badge.js";
import { Card, CardSection, ExpandSectionsPrompt } from "./comments/Card.js";
import { Comment } from "./comments/Comment.js";
import { Editor } from "./comments/Editor.js";
import { Form } from "./form/Form.js";
import { TextInput } from "./form/TextInput.js";
import {
Menu,
Expand Down Expand Up @@ -89,7 +90,7 @@ export const components: Components = {
Group: BadgeGroup,
},
Form: {
Root: (props) => <div>{props.children}</div>,
Root: Form,
TextInput: TextInput,
},
Menu: {
Expand Down
22 changes: 22 additions & 0 deletions packages/mantine/src/form/Form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { assertEmpty } from "@blocknote/core";
import { ComponentProps } from "@blocknote/react";

export const Form = (props: ComponentProps["Generic"]["Form"]["Root"]) => {
const { children, onSubmit, submitButton, ...rest } = props;

assertEmpty(rest);

return (
<form
className={"bn-form"}
onSubmit={(event) => {
// These forms have no action — a real submission would navigate.
event.preventDefault();
onSubmit?.();
}}
>
{children}
{submitButton === "none" ? null : submitButton}
</form>
);
};
12 changes: 7 additions & 5 deletions packages/mantine/src/form/TextInput.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { TextInput as MantineTextInput } from "@mantine/core";

import { assertEmpty, mergeCSSClasses } from "@blocknote/core";
import { ComponentProps } from "@blocknote/react";
import { ComponentProps, useMergeRefs, useAutoFocus } from "@blocknote/react";
import { forwardRef } from "react";

export const TextInput = forwardRef<
Expand All @@ -20,7 +20,6 @@ export const TextInput = forwardRef<
disabled,
onKeyDown,
onChange,
onSubmit,
autoComplete,
"aria-activedescendant": ariaActivedescendant,
rightSection,
Expand All @@ -29,26 +28,29 @@ export const TextInput = forwardRef<

assertEmpty(rest);

// Rationale (and the trap contract `data-autofocus` serves) in the hook.

const inputRef = useAutoFocus<HTMLInputElement>(autoFocus);
const setRefs = useMergeRefs([inputRef, ref]);

return (
<MantineTextInput
size={"xs"}
className={mergeCSSClasses(
className || "",
variant === "large" ? "bn-mt-input-large" : "",
)}
ref={ref}
ref={setRefs}
name={name}
label={label}
leftSection={icon}
value={value}
autoFocus={autoFocus}
data-autofocus={autoFocus ? "true" : undefined}
rightSection={rightSection}
placeholder={placeholder}
disabled={disabled}
onKeyDown={onKeyDown}
onChange={onChange}
onSubmit={onSubmit}
autoComplete={autoComplete}
aria-activedescendant={ariaActivedescendant}
/>
Expand Down
Loading
Loading