[morethanwords/tweb/master](https://github.com/morethanwords/tweb/tree/master) • [f57dbce](https://github.com/morethanwords/tweb/commit/f57dbcec34240e65f5ee4e1fe6626c26dfcf40f6) • _15 files, +1248/-61_
Highlight the found text in bubbles and search rows, and the quoted part on quote click

There was one highlight in the whole app — search rows made the matched
word bold by faking a `messageEntityHighlight` entity in
wrapMessageForReply — and nothing at all in the chat: jumping to a search
result or clicking a quote only flashed the bubble.

One helper now does it everywhere: `highlightText()` in
helpers/dom/textHighlight.ts describes the matched text as live Ranges over
the container's text nodes (entities, custom emoji, spoilers, code and
translations untouched; a multi-line match is a single range), re-finds it
when the container mutates or re-flows and collects itself once the
container leaves the document. Two paints:

- `::highlight()` (CSS Custom Highlight API) for chat-list rows — accent
  text like tdesktop/Android, white on the active row;
- `lineBoxes` for bubbles: an absolutely positioned overlay with one box
  per line stretched to the full line height. Browsers paint `::highlight`
  only glyph-high, which leaves gaps between wrapped lines; the overlay is
  a contiguous block like a selection and works without the API.

Matching follows the clients: a search query as a phrase, else every word
as a word prefix extended to the word's end with a shorter-prefix fallback
(tdesktop's FindSearchQueryHighlight); a quote is the exact text closest
to quote_offset with a whitespace-insensitive retry (findTwoWays).

Wiring: setLastMessage lights the query up in the message part of a row
and stamps it on the row, the list click carries it as
ChatSetPeerOptions.highlight, topbar search passes its query, the reply
click passes the manual quote — bubbles.highlightBubble paints it after
the scroll to the message settles (iOS): the whole text fades in selected,
holds, narrows down onto the match, stays four seconds and fades. Link
previews, time, reactions and code headers are not the text.

Also: [start-preview.sh](http://start-preview.sh/) disables pnpm's verify-deps-before-run — in a
worktree it tried to purge the symlinked node_modules.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

[#webk](?q=%23webk)