Skip to content

Adjust selection after triple click#4512

Merged
fantactuka merged 1 commit into
mainfrom
triple-click
May 18, 2023
Merged

Adjust selection after triple click#4512
fantactuka merged 1 commit into
mainfrom
triple-click

Conversation

@fantactuka

Copy link
Copy Markdown
Collaborator

Triple click expands selection to cover whole element, but also moves focus node to the next element sibling. So even though visually it looks like single text block is selected, selection is also expanded to the next line. If we try to modify such selection two blocks are affected.

Easiest way to reproduce: have two paragraphs, tripple click on first, convert into heading, then both paragraphs will be converted into headings. Another example is tripple click within table cell, and pressing delete: it selects current cell and beginning of the next one. Hitting delete will completely delete one of the cells

Before:

Screen.Recording.2023-05-17.at.5.52.23.PM.mov

After:

Screen.Recording.2023-05-17.at.5.54.29.PM.mov

@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 May 17, 2023
@vercel

vercel Bot commented May 17, 2023

Copy link
Copy Markdown

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

Name Status Preview Updated (UTC)
lexical ✅ Ready (Inspect) Visit Preview May 17, 2023 9:55pm
lexical-playground ✅ Ready (Inspect) Visit Preview May 17, 2023 9:55pm

@github-actions

Copy link
Copy Markdown

size-limit report 📦

Path Size Loading time (3g) Running time (snapdragon) Total time
packages/lexical/dist/Lexical.js 27.25 KB (+0.15% 🔺) 545 ms (+0.15% 🔺) 443 ms (-11.32% 🔽) 988 ms
packages/lexical-rich-text/dist/LexicalRichText.js 38.2 KB (+0.11% 🔺) 764 ms (+0.11% 🔺) 410 ms (+19.08% 🔺) 1.2 s
packages/lexical-plain-text/dist/LexicalPlainText.js 38.17 KB (+0.12% 🔺) 764 ms (+0.12% 🔺) 741 ms (+36.61% 🔺) 1.6 s

@zurfyx zurfyx left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Uh, nice! This one has been there forever. Doesn't close any issue?

@fantactuka

fantactuka commented May 17, 2023

Copy link
Copy Markdown
Collaborator Author

Fixes #2648, #2660 and #3784

@fantactuka fantactuka merged commit c0e7e78 into main May 18, 2023
@fantactuka fantactuka deleted the triple-click branch May 18, 2023 20:27
vuamitom pushed a commit to bitbriks/lexical that referenced this pull request May 19, 2023
@LuciNyan

Copy link
Copy Markdown
Contributor

Incredible!

This was referenced May 23, 2023
flavorjones added a commit to basecamp/lexxy that referenced this pull request May 13, 2026
…m running.

Lexical's onClick handler implements a triple-click handler that is
trivial/anemic/naïve. The intention of the change, made in
facebook/lexical#4512, seems to be to deal with browsers'
"overselection" behavior, where a triple-click selection might end at
offset 0 of the following block, which can cause issues when
transforming the selection. But the implementation breaks many common
real-world use cases.

An upstream bug report was filed in June 2025 for this behavior:

    facebook/lexical#7592

Just to name two common impacted scenarios that are top-of-mind:

- triple-clicking in a paragraph with soft line breaks (`<br>` tags)
- triple-click-dragging to select multiple lines

The specific motivating reason for Lexical's handler seems to be that
the "Header" tool in Lexical doesn't handle this overselection and
will header-ify the following line; and that table cells can be
deleted entirely once selected.

However, Lexxy has its own "Header" tool that doesn't have this issue;
and Lexical tables no longer exhibit the cell-deletion behavior. I
think it might be better to improve the formatting tool(s) than to
hack the selection mechanism.

Hopefully, we can remove this once Lexical addresses this
behavior. Some possible upstream approaches for that might be:

- Move the existing selection handling logic into a real handler that
  applications can pre-empt.
- Fix the selection behavior, or drop the triple-click handler
  completely.

ref: https://app.basecamp.com/2914079/buckets/41746046/card_tables/cards/9861391060
flavorjones added a commit to basecamp/lexxy that referenced this pull request May 14, 2026
…m running.

Lexical's onClick handler implements a triple-click handler that is
trivial/anemic/naïve. The intention of the change, made in
facebook/lexical#4512, seems to be to deal with browsers'
"overselection" behavior, where a triple-click selection might end at
offset 0 of the following block, which can cause issues when
transforming the selection. But the implementation breaks many common
real-world use cases.

An upstream bug report was filed in June 2025 for this behavior:

    facebook/lexical#7592

Just to name two common impacted scenarios that are top-of-mind:

- triple-clicking in a paragraph with soft line breaks (`<br>` tags)
- triple-click-dragging to select multiple lines

The specific motivating reason for Lexical's handler seems to be that
the "Header" tool in Lexical doesn't handle this overselection and
will header-ify the following line; and that table cells can be
deleted entirely once selected.

However, Lexxy has its own "Header" tool that doesn't have this issue;
and Lexical tables no longer exhibit the cell-deletion behavior. I
think it might be better to improve the formatting tool(s) than to
hack the selection mechanism.

Hopefully, we can remove this once Lexical addresses this
behavior. Some possible upstream approaches for that might be:

- Move the existing selection handling logic into a real handler that
  applications can pre-empt.
- Fix the selection behavior, or drop the triple-click handler
  completely.

ref: https://app.basecamp.com/2914079/buckets/41746046/card_tables/cards/9861391060
flavorjones added a commit to basecamp/lexxy that referenced this pull request May 14, 2026
…m running. (#1050)

Lexical's onClick handler implements a triple-click handler that is
trivial/anemic/naïve. The intention of the change, made in
facebook/lexical#4512, seems to be to deal with browsers'
"overselection" behavior, where a triple-click selection might end at
offset 0 of the following block, which can cause issues when
transforming the selection. But the implementation breaks many common
real-world use cases.

An upstream bug report was filed in June 2025 for this behavior:

    facebook/lexical#7592

Just to name two common impacted scenarios that are top-of-mind:

- triple-clicking in a paragraph with soft line breaks (`<br>` tags)
- triple-click-dragging to select multiple lines

The specific motivating reason for Lexical's handler seems to be that
the "Header" tool in Lexical doesn't handle this overselection and
will header-ify the following line; and that table cells can be
deleted entirely once selected.

However, Lexxy has its own "Header" tool that doesn't have this issue;
and Lexical tables no longer exhibit the cell-deletion behavior. I
think it might be better to improve the formatting tool(s) than to
hack the selection mechanism.

Hopefully, we can remove this once Lexical addresses this
behavior. Some possible upstream approaches for that might be:

- Move the existing selection handling logic into a real handler that
  applications can pre-empt.
- Fix the selection behavior, or drop the triple-click handler
  completely.

ref: https://app.basecamp.com/2914079/buckets/41746046/card_tables/cards/9861391060
etrepum pushed a commit to etrepum/lexical that referenced this pull request May 19, 2026
…le-click workaround

Fixes facebook#7592.

\## Context

Browsers expand triple-click selections to cover an entire block, but
leave the focus point at offset 0 of the *next* block. The selection
visually looks like one paragraph is selected, but actually extends
one position into the following block.

Historically, this selection behavior caused some issues, including:

- facebook#2648 Converting to other
  blocks after selection (e.g. Heading)
- facebook#2660 Over-selection
- facebook#3784 Selections have
  incorrect format
- and another bug with table cell select-and-deletion mentioned in facebook#4512

PR facebook#4512 worked around these bugs in `onClick` (`LexicalEvents.ts`) by
detecting `event.detail === 3` and forcibly re-selecting the parent
block..

The `onClick` workaround is a poor fit, however, because it mutates
the user's selection on *every* triple-click — breaking common cases
like triple-clicking a paragraph with soft line breaks:(`<br>`), or
triple-click-and-drag to select multiple lines, leading to issues like
the one described in facebook#7592

\## Status of the original motivations

A lot has changed since facebook#4512!

- Table cell deletion was fixed independently in facebook#7213; the tables no
  longer rely on the `onClick` workaround.
- facebook#2660 No longer manifests without the triple-click handler
- facebook#3784 No longer manifests without the triple-click handler
- facebook#2648 The heading format tool (and related tools — paragraph, quote,
  code block — all routed through `$setBlocksType`) is the only
  remaining caller depending on the workaround.

Which means the triple-click handler can be removed if
`$setBlocksType` is updated to handle overselection.

\## This change

Fix `$setBlocksType` (`@lexical/selection`) to skip converting the
focus's block when no content of that block is actually selected —
specifically, when the focus is a text-type point at offset 0 of the
block's first descendant and the block differs from the anchor's
block. This matches the visual semantics users expect, and covers both
triple-click overselection and deliberate
drag-select-to-start-of-next-block.

With that root cause fixed, the `onClick` triple-click workaround is
removed.

\## Tests

- Existing e2e tests for triple-click + heading conversion continue
  to pass without the `onClick` workaround
  (`Selection.spec.mjs`, `TextFormatting.spec.mjs`).
- `$setBlocksType` unit tests in
  `packages/lexical-selection/src/__tests__/unit/LexicalSelection.test.tsx`
  continue to pass; the fix only affects text-type focus points, so
  the existing element-point-based tests are unchanged.
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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants