Skip to content
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

fix: end-of-line cursor issue in Safari #6282

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

sodenn
Copy link

@sodenn sodenn commented Jun 9, 2024

Description

This PR addresses a bug in Safari where the cursor cannot be positioned at the end of a line when the line ends with a contenteditable=false element.

Closes #4487

Of course, other text editors like ProseMirror have the same problem, and they work around it by adding an <img> element before the line break. This PR implements a similar approach and adds an <img> element before the __lexicalLineBreak element.

Please note that there is a method called isManagedLineBreak in LexicalMutations.ts that accesses __lexicalLineBreak. It is unclear to me if the new <img> element causes any issues in this context.

❌ Before
2024-06-11 17 05 33

✅ After
2024-06-11 17 03 54

For further reference, see:

Copy link

vercel bot commented Jun 9, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
lexical ❌ Failed (Inspect) Jun 25, 2024 6:20pm
lexical-playground ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 25, 2024 6:20pm

@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jun 9, 2024
Copy link

github-actions bot commented Jun 9, 2024

size-limit report 📦

Path Size
lexical - cjs 28.47 KB (0%)
lexical - esm 28.28 KB (0%)
@lexical/rich-text - cjs 36.91 KB (0%)
@lexical/rich-text - esm 28.09 KB (0%)
@lexical/plain-text - cjs 35.54 KB (0%)
@lexical/plain-text - esm 25.3 KB (0%)
@lexical/react - cjs 38.82 KB (0%)
@lexical/react - esm 29.27 KB (0%)

@StyleT
Copy link
Contributor

StyleT commented Jun 10, 2024

Hi!

Can you pls submit screen recordings before / after fix and try to update unit / e2e test?

And thank you for your contribution!

@sodenn
Copy link
Author

sodenn commented Jun 11, 2024

@StyleT I've updated the PR and added screen recordings. However, adding tests is a bit tricky since this is a visual browser bug. Meaning, the getSelection position data is correct - even when the cursor is drawn at the wrong position.
Maybe we could add a test that captures the cursor position in a screenshot. But this could lead to a flaky test because of the cursor blinking.

@ccapndave
Copy link

Thanks so much for doing this! This bug has been the bane of our lives :)

}
} else if (nextLineBreak) {
const element = document.createElement('br');
// Workaround for a bug in Safari where the cursor cannot be placed at the
// end of a line.
if (IS_SAFARI) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works great on desktop Safari, but not on mobile Safari. I think it needs to be IS_SAFARI || IS_IOS in order to work on both.

@StyleT
Copy link
Contributor

StyleT commented Jun 24, 2024

Hi! Sorry for a long reply here...

I see that this PR fixes the issue with the end-of-line cursor, however when image (as in your videos) is the first element on the line - now you can't place cursor at the start-of-line.

Am I missing something?

@sodenn
Copy link
Author

sodenn commented Jun 25, 2024

Hi! Sorry for a long reply here...

I see that this PR fixes the issue with the end-of-line cursor, however when image (as in your videos) is the first element on the line - now you can't place cursor at the start-of-line.

Am I missing something?

It is a different problem 😕. The cursor is at the beginning of the line, but now the image hides the cursor.

To clarify, for other elements than images (div, span, etc.), the cursor is not hidden, but is slightly inside the elements. I see exactly the same behavior in other text editors (probably another Safari bug?).

This is the behavior when a span is used instead of an img:
2024-06-25 19 37 27

I still believe in most cases this is an improvement to the Safari users.

@wouterlemcke
Copy link

Any progress on this? This is a big issue for our project. Would be great if this get fixed! If there is anything I can do to help, please let me know!

@ccapndave
Copy link

It was also a big issue for us, so we've been using the PR branch directly and so far haven't had any issue.

@wouterlemcke
Copy link

It was also a big issue for us, so we've been using the PR branch directly and so far haven't had any issue.

The branch from @sodenn fork you mean? I installed it using npm install "https://github.com/sodenn/lexical.git#fix/cursor-placement-safari" --save, but I don't see an update (locally) in the changed file..

Probably I'm doing something stupid, is this the same thing you used?

@ccapndave
Copy link

So actually I ended up writing a script to use yarn patch and yarn patch-commit to update the build in-place in node_modules. I've pasted it in here in case its any use to you!

#!/usr/bin/env bash
set -e

if [ $# -ne 2 ]; then
    echo "Given a branch and a repo, this builds the lexical package and records a patch in .yarn/patches."
    echo "Usage: yarn patch:lexical <branch> <repo>"
    exit 1
fi

BRANCH=$1
REPO=$2

# Make a temporary directory
TEMP_DIR=$(mktemp -d)

# Clone the fork
git clone -b $BRANCH --single-branch $REPO $TEMP_DIR

# Change directory to the temporary directory
cd $TEMP_DIR

# Set the required node version
echo "nodejs 20.11.0" > ./.tool-versions 

# Build Lexical
npm install
npm run build-release

# Change back to the original directory
cd -

# Get all the lexical dependencies
DEPS=$(jq -r '.dependencies | keys | map(select(test("lexical")))' package.json)
readarray -t DEP_NAMES <<< "$(echo $DEPS | jq -r '.[]')"

# Find the folder for each dependency
for DEP in "${DEP_NAMES[@]}"; do
    # Loop through all directories in $TEMP_DIR/packages
    for DIR in $TEMP_DIR/packages/*; do
        if [ -d "$DIR" ]; then  # Ensure $dir is a directory
            # Check if package.json exists in the directory
            if [ -f "$DIR/package.json" ]; then
                # Extract the name field from package.json
                PACKAGE_NAME=$(jq -r '.name' "$DIR/package.json")
                # Compare with the current dependency name
                if [[ "$PACKAGE_NAME" == "$DEP" ]]; then
                    echo "Patching $PACKAGE_NAME (in $DIR)"

                    echo "PACKAGE_NAME: $PACKAGE_NAME"
                    echo "DIR: $DIR"
                    echo "TEMP_DIR: $TEMP_DIR"
                    echo "DEP: $DEP"

                    # Build the patch
                    PATCH_PATH=$(yarn patch $PACKAGE_NAME --json | jq -r '.path')
                    cp -R $DIR/dist/* $PATCH_PATH

                    # Determine if there is actually a difference
                    set +e
                    git diff --quiet --no-index $PATCH_PATH ./node_modules/$DEP
                    if [ $? -eq 0 ]; then
                        echo "No changes detected for $PACKAGE_NAME."
                    else
                        echo "Patching..."
                        yarn patch-commit -s $PATCH_PATH
                        echo "Generated patch for $PACKAGE_NAME."
                    fi
                    set -e

                    echo
                fi
            fi
        fi
    done
done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. safari-bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Bug: Cannot place cursor at the end of the line (Safari)
6 participants