From 65ef700fdc0c744188f1c845654a4d3cd69c71ff Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Fri, 2 Aug 2024 06:47:56 -0700 Subject: [PATCH] Mobile, Desktop: Improve RTL support in the Markdown editor (#10810) --- .eslintignore | 1 + .gitignore | 1 + packages/editor/CodeMirror/createEditor.ts | 2 + .../utils/biDirectionalTextExtension.ts | 40 +++++++++++++++++++ 4 files changed, 44 insertions(+) create mode 100644 packages/editor/CodeMirror/utils/biDirectionalTextExtension.ts diff --git a/.eslintignore b/.eslintignore index 4cce905f2..360f34c05 100644 --- a/.eslintignore +++ b/.eslintignore @@ -800,6 +800,7 @@ packages/editor/CodeMirror/testUtil/loadLanguages.js packages/editor/CodeMirror/testUtil/pressReleaseKey.js packages/editor/CodeMirror/testUtil/typeText.js packages/editor/CodeMirror/theme.js +packages/editor/CodeMirror/utils/biDirectionalTextExtension.js packages/editor/CodeMirror/utils/formatting/RegionSpec.js packages/editor/CodeMirror/utils/formatting/findInlineMatch.test.js packages/editor/CodeMirror/utils/formatting/findInlineMatch.js diff --git a/.gitignore b/.gitignore index c79632360..e2e3d6b80 100644 --- a/.gitignore +++ b/.gitignore @@ -779,6 +779,7 @@ packages/editor/CodeMirror/testUtil/loadLanguages.js packages/editor/CodeMirror/testUtil/pressReleaseKey.js packages/editor/CodeMirror/testUtil/typeText.js packages/editor/CodeMirror/theme.js +packages/editor/CodeMirror/utils/biDirectionalTextExtension.js packages/editor/CodeMirror/utils/formatting/RegionSpec.js packages/editor/CodeMirror/utils/formatting/findInlineMatch.test.js packages/editor/CodeMirror/utils/formatting/findInlineMatch.js diff --git a/packages/editor/CodeMirror/createEditor.ts b/packages/editor/CodeMirror/createEditor.ts index a78814886..c6079b36a 100644 --- a/packages/editor/CodeMirror/createEditor.ts +++ b/packages/editor/CodeMirror/createEditor.ts @@ -31,6 +31,7 @@ import getScrollFraction from './getScrollFraction'; import CodeMirrorControl from './CodeMirrorControl'; import insertLineAfter from './editorCommands/insertLineAfter'; import handlePasteEvent from './utils/handlePasteEvent'; +import biDirectionalTextExtension from './utils/biDirectionalTextExtension'; const createEditor = ( parentElement: HTMLElement, props: EditorProps, @@ -282,6 +283,7 @@ const createEditor = ( // Apply styles to entire lines (block-display decorations) decoratorExtension, + biDirectionalTextExtension, // Adds additional CSS classes to tokens (the default CSS classes are // auto-generated and thus unstable). diff --git a/packages/editor/CodeMirror/utils/biDirectionalTextExtension.ts b/packages/editor/CodeMirror/utils/biDirectionalTextExtension.ts new file mode 100644 index 000000000..ef8f09d12 --- /dev/null +++ b/packages/editor/CodeMirror/utils/biDirectionalTextExtension.ts @@ -0,0 +1,40 @@ +import { Extension, RangeSetBuilder } from '@codemirror/state'; +import { Decoration, DecorationSet, EditorView, ViewPlugin, ViewUpdate } from '@codemirror/view'; + +const autoTextDirectionDecoration = Decoration.line({ + attributes: { dir: 'auto' }, +}); + +const biDirectionalTextExtension: Extension = [ + EditorView.perLineTextDirection.of(true), + ViewPlugin.fromClass(class { + public decorations: DecorationSet; + public constructor(view: EditorView) { + this.decorations = this.buildDecorations(view); + } + + public update(update: ViewUpdate) { + if (update.docChanged || update.viewportChanged) { + this.decorations = this.buildDecorations(update.view); + } + } + + private buildDecorations(view: EditorView) { + const builder = new RangeSetBuilder(); + for (const { from, to } of view.visibleRanges) { + const fromLine = view.state.doc.lineAt(from); + const toLine = view.state.doc.lineAt(to); + + for (let i = fromLine.number; i <= toLine.number; i++) { + const line = view.state.doc.line(i); + if (line.text) { + builder.add(line.from, line.from, autoTextDirectionDecoration); + } + } + } + return builder.finish(); + } + }, { decorations: v => v.decorations }), +]; + +export default biDirectionalTextExtension;