Repository navigation
Improve RTL editor layout and core interactions #3333
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| { | ||
| "playground": true, | ||
| "docs": false, | ||
| "author": "", | ||
| "tags": ["Basic"] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| # Right-to-left (RTL) | ||
|
|
||
| A Hebrew-localized editor with Hebrew, Arabic, and mixed English text. Use the Hebrew dictionary, Mantine's `DirectionProvider`, and `dir="rtl"` on `BlockNoteView` to localize the UI and mirror the layout while keeping code left-to-right. The provider uses `initialDirection="rtl"` and `detectDirection={false}` so this example stays RTL independently of the surrounding playground. | ||
|
|
||
| **Try it out!** Edit the nested lists, open a block menu, edit the link, or type `/` and `:sm` in the empty paragraph to try the slash menu and emoji picker. | ||
|
|
||
| **Relevant Docs:** | ||
|
|
||
| - [Editor Setup](/docs/getting-started/editor-setup) | ||
| - [Localization](/docs/features/localization) | ||
| - [Mantine RTL setup](https://mantine.dev/styles/rtl/) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="UTF-8" /> | ||
| <meta | ||
| name="viewport" | ||
| content="width=device-width, initial-scale=1.0, interactive-widget=resizes-content" | ||
| /> | ||
| <title>Right-to-left (RTL)</title> | ||
| <script> | ||
| <!-- AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY --> | ||
| </script> | ||
| </head> | ||
| <body> | ||
| <div id="root"></div> | ||
| <script type="module" src="./main.tsx"></script> | ||
| </body> | ||
| </html> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| // AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY | ||
| import React from "react"; | ||
| import { createRoot } from "react-dom/client"; | ||
| import App from "./src/App.jsx"; | ||
|
|
||
| const root = createRoot(document.getElementById("root")!); | ||
| root.render( | ||
| <React.StrictMode> | ||
| <App /> | ||
| </React.StrictMode>, | ||
| ); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| { | ||
| "name": "@blocknote/example-basic-rtl", | ||
| "description": "AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY", | ||
| "type": "module", | ||
| "private": true, | ||
| "version": "0.12.4", | ||
| "scripts": { | ||
| "start": "vite", | ||
| "dev": "vite", | ||
| "build:prod": "tsc && vite build", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| "preview": "vite preview" | ||
| }, | ||
| "dependencies": { | ||
| "@blocknote/ariakit": "latest", | ||
| "@blocknote/core": "latest", | ||
| "@blocknote/mantine": "latest", | ||
| "@blocknote/react": "latest", | ||
| "@blocknote/shadcn": "latest", | ||
| "@mantine/core": "^9.0.2", | ||
| "@mantine/hooks": "^9.0.2", | ||
| "react": "^19.2.3", | ||
| "react-dom": "^19.2.3" | ||
| }, | ||
| "devDependencies": { | ||
| "@types/react": "^19.2.3", | ||
| "@types/react-dom": "^19.2.3", | ||
| "@vitejs/plugin-react": "^6.0.1", | ||
| "vite": "^8.0.0" | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| import "@blocknote/core/fonts/inter.css"; | ||
| import { he } from "@blocknote/core/locales"; | ||
| import { BlockNoteView } from "@blocknote/mantine"; | ||
| import "@blocknote/mantine/style.css"; | ||
| import { useCreateBlockNote } from "@blocknote/react"; | ||
| import { DirectionProvider } from "@mantine/core"; | ||
|
|
||
| export default function App() { | ||
| const editor = useCreateBlockNote({ | ||
| dictionary: he, | ||
| initialContent: [ | ||
| { | ||
| type: "heading", | ||
| props: { level: 2 }, | ||
| content: "שלום — مرحباً", | ||
| }, | ||
| { | ||
| type: "paragraph", | ||
| content: "עורך מימין לשמאל — محرر من اليمين إلى اليسار", | ||
| }, | ||
| { | ||
| type: "paragraph", | ||
| content: "עברית, العربية ו-English (123) — טקסט מעורב / نص مختلط.", | ||
| }, | ||
| { | ||
| type: "bulletListItem", | ||
| content: "רשימה עם פריטים מקוננים", | ||
| children: [ | ||
| { type: "bulletListItem", content: "פריט פנימי — بند فرعي" }, | ||
| { | ||
| type: "bulletListItem", | ||
| content: "English inside an RTL list (456)", | ||
| }, | ||
| ], | ||
| }, | ||
| { type: "numberedListItem", content: "الخطوة الأولى — שלב ראשון" }, | ||
| { type: "numberedListItem", content: "الخطوة الثانية — שלב שני" }, | ||
| { type: "checkListItem", content: "משימה לבדיקה — مهمة للتجربة" }, | ||
| { type: "quote", content: "اقتباس قصير — ציטוט קצר" }, | ||
| { | ||
| type: "toggleListItem", | ||
| content: "פרטים נוספים — تفاصيل إضافية", | ||
| children: [ | ||
| { | ||
| type: "paragraph", | ||
| content: "אפשר לערוך גם כאן — يمكنك الكتابة هنا أيضاً.", | ||
| }, | ||
| ], | ||
| }, | ||
| { | ||
| type: "paragraph", | ||
| content: [ | ||
| { type: "text", text: "קישור לדוגמה — ", styles: {} }, | ||
| { | ||
| type: "link", | ||
| href: "https://www.blocknotejs.org", | ||
| content: "توثيق BlockNote", | ||
| }, | ||
| ], | ||
| }, | ||
| { type: "codeBlock", content: 'const greeting = "שלום — مرحباً";' }, | ||
| { type: "paragraph" }, | ||
| ], | ||
| }); | ||
|
|
||
| // Keep Mantine's direction context and the editor's DOM direction in sync, | ||
| // without detecting or changing the surrounding playground's direction. | ||
| return ( | ||
| <DirectionProvider initialDirection="rtl" detectDirection={false}> | ||
| <BlockNoteView editor={editor} dir="rtl" lang="he" /> | ||
| </DirectionProvider> | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| { | ||
| "__comment": "AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY", | ||
| "compilerOptions": { | ||
| "target": "ESNext", | ||
| "useDefineForClassFields": true, | ||
| "lib": ["DOM", "DOM.Iterable", "ESNext"], | ||
| "allowJs": false, | ||
| "skipLibCheck": true, | ||
| "allowSyntheticDefaultImports": true, | ||
| "strict": true, | ||
| "forceConsistentCasingInFileNames": true, | ||
| "module": "ESNext", | ||
| "moduleResolution": "bundler", | ||
| "resolveJsonModule": true, | ||
| "isolatedModules": true, | ||
| "noEmit": true, | ||
| "jsx": "react-jsx", | ||
| "composite": true, | ||
| "paths": { | ||
| "@shared/*": ["../../../shared/*"] | ||
| } | ||
| }, | ||
| "include": ["."], | ||
| "__ADD_FOR_LOCAL_DEV_references": [ | ||
| { | ||
| "path": "../../../packages/core/" | ||
| }, | ||
| { | ||
| "path": "../../../packages/react/" | ||
| } | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| /// <reference types="vite/client" /> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| // AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY | ||
| import react from "@vitejs/plugin-react"; | ||
| import * as fs from "fs"; | ||
| import * as path from "path"; | ||
|
Comment on lines
+3
to
+4
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| import { defineConfig } from "vite"; | ||
| // https://vitejs.dev/config/ | ||
| export default defineConfig(((conf: { command: string }) => ({ | ||
| plugins: [react()], | ||
| optimizeDeps: {}, | ||
| build: { | ||
| sourcemap: true, | ||
| }, | ||
| resolve: { | ||
| alias: | ||
| conf.command === "build" || | ||
| !fs.existsSync(path.resolve(__dirname, "../../../packages/core/src")) | ||
| ? {} | ||
| : ({ | ||
| // The repo-wide alias for the shared test-utils directory (private, | ||
| // so it only resolves inside the monorepo). Harmless for examples | ||
| // that don't use it. | ||
| "@shared": path.resolve(__dirname, "../../../shared/"), | ||
| // Comment out the lines below to load a built version of blocknote | ||
| // or, keep as is to load live from sources with live reload working | ||
| "@blocknote/core": path.resolve( | ||
| __dirname, | ||
| "../../../packages/core/src/", | ||
| ), | ||
| "@blocknote/react": path.resolve( | ||
| __dirname, | ||
| "../../../packages/react/src/", | ||
| ), | ||
| } as any), | ||
| }, | ||
| })) as Parameters<typeof defineConfig>[0]); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generate a doctype for the standalone example.
Without a doctype, the standalone page uses quirks mode, while the playground uses standards mode. This changes browser layout rules and makes the standalone example an unreliable comparison with the playground. Update
packages/dev-scripts/examples/template-react/index.html.template.tsxand regenerate the page. (html.spec.whatwg.org)HTMLHint (1.9.2)
[error] 1-1: Doctype must be declared before any non-comment content.
(doctype-first)
Source: Linters/SAST tools